From 8a3e4f14d1ab4149befdf84c8e4cf546d13bd3f5 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Sun, 25 Jul 2021 04:06:02 +0200 Subject: [PATCH 001/171] Add tests and `.qlref` --- .../Security/CWE-614/InsecureCookie.qlref | 1 + .../Security/CWE-614/django_bad.py | 13 +++++++ .../Security/CWE-614/django_good.py | 19 +++++++++++ .../query-tests/Security/CWE-614/flask_bad.py | 34 +++++++++++++++++++ .../Security/CWE-614/flask_good.py | 34 +++++++++++++++++++ 5 files changed, 101 insertions(+) create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.qlref create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-614/django_good.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.qlref b/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.qlref new file mode 100644 index 00000000000..378d5dcae1a --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-614/InsecureCookie.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py new file mode 100644 index 00000000000..877231f8f14 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py @@ -0,0 +1,13 @@ +import django.http + + +def django_response(request): + resp = django.http.HttpResponse() + resp.set_cookie("name", "value", secure=None) + return resp + + +def django_response(request): + resp = django.http.HttpResponse() + resp.set_cookie("name", "value") + return resp diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/django_good.py b/python/ql/test/experimental/query-tests/Security/CWE-614/django_good.py new file mode 100644 index 00000000000..ebf16236de2 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/django_good.py @@ -0,0 +1,19 @@ +import django.http + + +def django_response(request): + resp = django.http.HttpResponse() + resp['Set-Cookie'] = "name=value; Secure;" + return resp + + +def django_response(request): + resp = django.http.HttpResponse() + resp.set_cookie("name", "value", secure=True) + return resp + + +def indeterminate(secure): + resp = django.http.HttpResponse() + resp.set_cookie("name", "value", secure) + return resp diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py new file mode 100644 index 00000000000..7c7d6e8acd0 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py @@ -0,0 +1,34 @@ +from flask import Flask, request, make_response, Response + +app = Flask(__name__) + + +@app.route("/false") +def false(): + resp = make_response() + resp.set_cookie("name", value="value", secure=False) + return resp + + +@app.route("/none") +def none(): + resp = make_response() + resp.set_cookie("name", value="value", secure=None) + return resp + + +@app.route("/flask_Response") +def flask_Response(): + resp = Response() + resp.headers['Set-Cookie'] = "name=value;" + return resp + + +@app.route("/flask_make_response") +def flask_make_response(): + resp = make_response("hello") + resp.headers['Set-Cookie'] = "name=value;" + return resp + +# if __name__ == "__main__": +# app.run(debug=True) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py new file mode 100644 index 00000000000..05ee3f28657 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py @@ -0,0 +1,34 @@ +from flask import Flask, request, make_response, Response + +app = Flask(__name__) + + +@app.route("/true") +def true(): + resp = make_response() + resp.set_cookie("name", value="value", secure=True) + return resp + + +@app.route("/flask_Response") +def flask_Response(): + resp = Response() + resp.headers['Set-Cookie'] = "name=value; Secure;" + return resp + + +@app.route("/flask_make_response") +def flask_make_response(): + resp = make_response("hello") + resp.headers['Set-Cookie'] = "name=value; Secure;" + return resp + + +def indeterminate(secure): + resp = make_response() + resp.set_cookie("name", value="value", secure=secure) + return resp + + +# if __name__ == "__main__": +# app.run(debug=True) From c8983be947adac8c3faba902056c9c898cf848af Mon Sep 17 00:00:00 2001 From: jorgectf Date: Sun, 25 Jul 2021 04:06:44 +0200 Subject: [PATCH 002/171] Add query --- .../Security/CWE-614/InsecureCookie.ql | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql new file mode 100644 index 00000000000..2405d6ddd4e --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -0,0 +1,30 @@ +/** + * @name Failure to use secure cookies + * @description Insecure cookies may be sent in cleartext, which makes them vulnerable to + * interception. + * @kind problem + * @problem.severity error + * @id py/insecure-cookie + * @tags security + * external/cwe/cwe-614 + */ + +// determine precision above +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.Concepts +import experimental.semmle.python.Concepts + +from HeaderDeclaration headerWrite, False f, None n +where + exists(StrConst headerName, StrConst headerValue | + headerName.getText() = "Set-Cookie" and + DataFlow::exprNode(headerName).(DataFlow::LocalSourceNode).flowsTo(headerWrite.getNameArg()) and + not headerValue.getText().regexpMatch(".*; *Secure;.*") and + DataFlow::exprNode(headerValue).(DataFlow::LocalSourceNode).flowsTo(headerWrite.getValueArg()) + ) + or + [DataFlow::exprNode(f), DataFlow::exprNode(n)] + .(DataFlow::LocalSourceNode) + .flowsTo(headerWrite.(DataFlow::CallCfgNode).getArgByName("secure")) +select headerWrite, "Cookie is added to response without the 'secure' flag being set." From 4f68a1777ce5efe87507dce2847b3c4dcfb15066 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Sun, 25 Jul 2021 04:07:05 +0200 Subject: [PATCH 003/171] Write documentation and example --- .../Security/CWE-614/InsecureCookie.py | 15 +++++++++++ .../Security/CWE-614/InsecureCookie.qhelp | 26 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 python/ql/src/experimental/Security/CWE-614/InsecureCookie.py create mode 100644 python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.py b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.py new file mode 100644 index 00000000000..54bbeff7d12 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.py @@ -0,0 +1,15 @@ +from flask import Flask, request, make_response, Response + + +@app.route("/true") +def true(): + resp = make_response() + resp.set_cookie("name", value="value", secure=True) + return resp + + +@app.route("/flask_make_response") +def flask_make_response(): + resp = make_response("hello") + resp.headers['Set-Cookie'] = "name=value; Secure;" + return resp \ No newline at end of file diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp new file mode 100644 index 00000000000..ab5e3031629 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp @@ -0,0 +1,26 @@ + + + + +

Failing to set the 'secure' flag on a cookie can cause it to be sent in cleartext. +This makes it easier for an attacker to intercept.

+
+ + +

Always set secure to True or add "; Secure;" to the cookie's raw value.

+
+ + +

This example shows two ways of adding a cookie to a Flask response. The first way uses set_cookie's +secure flag and the second adds the secure flag in the cookie's raw value.

+ +
+ + +
  • Detectify: Cookie lack Secure flag.
  • +
  • PortSwigger: TLS cookie without secure flag set.
  • +
    + +
    \ No newline at end of file From 65044293dd680552ac9782656d48354e0fa06b42 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Sun, 25 Jul 2021 17:53:58 +0200 Subject: [PATCH 004/171] Add `CookieWrite` concept --- .../experimental/semmle/python/Concepts.qll | 58 +++++++++++++++++++ .../semmle/python/frameworks/Django.qll | 11 ++++ 2 files changed, 69 insertions(+) diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll index 809176a9d52..56543246784 100644 --- a/python/ql/src/experimental/semmle/python/Concepts.qll +++ b/python/ql/src/experimental/semmle/python/Concepts.qll @@ -252,3 +252,61 @@ class HeaderDeclaration extends DataFlow::Node { */ DataFlow::Node getValueArg() { result = range.getValueArg() } } + +module ExperimentalHTTP { + /** + * A data-flow node that sets a cookie in an HTTP response. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `HTTP::CookieWrite::Range` instead. + */ + class CookieWrite extends DataFlow::Node { + CookieWrite::Range range; + + CookieWrite() { this = range } + + /** + * Gets the argument, if any, specifying the raw cookie header. + */ + DataFlow::Node getHeaderArg() { result = range.getHeaderArg() } + + /** + * Gets the argument, if any, specifying the cookie name. + */ + DataFlow::Node getNameArg() { result = range.getNameArg() } + + /** + * Gets the argument, if any, specifying the cookie value. + */ + DataFlow::Node getValueArg() { result = range.getValueArg() } + } + + /** Provides a class for modeling new cookie writes on HTTP responses. */ + module CookieWrite { + /** + * A data-flow node that sets a cookie in an HTTP response. + * + * Note: we don't require that this redirect must be sent to a client (a kind of + * "if a tree falls in a forest and nobody hears it" situation). + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `HttpResponse` instead. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets the argument, if any, specifying the raw cookie header. + */ + abstract DataFlow::Node getHeaderArg(); + + /** + * Gets the argument, if any, specifying the cookie name. + */ + abstract DataFlow::Node getNameArg(); + + /** + * Gets the argument, if any, specifying the cookie value. + */ + abstract DataFlow::Node getValueArg(); + } + } +} diff --git a/python/ql/src/experimental/semmle/python/frameworks/Django.qll b/python/ql/src/experimental/semmle/python/frameworks/Django.qll index c525b73b40e..da7db6fd18b 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Django.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Django.qll @@ -75,6 +75,17 @@ private module PrivateDjango { override DataFlow::Node getValueArg() { result = headerInput } } + + class DjangoSetCookieCall extends DataFlow::CallCfgNode, + ExperimentalHTTP::CookieWrite::Range { + DjangoSetCookieCall() { this = baseClassRef().getMember("set_cookie").getACall() } + + override DataFlow::Node getHeaderArg() { none() } + + override DataFlow::Node getNameArg() { result = this.getArg(0) } + + override DataFlow::Node getValueArg() { result = this.getArg(1) } + } } } } From 983465963aeeb403673ffce9ab4b61c275bd1af3 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Sun, 25 Jul 2021 18:18:29 +0200 Subject: [PATCH 005/171] Polish `CookieWrite` --- .../Security/CWE-614/InsecureCookie.ql | 18 +++++++++++------- .../semmle/python/frameworks/Flask.qll | 16 ++++++++++++++++ .../query-tests/Security/CWE-614/django_bad.py | 2 +- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index 2405d6ddd4e..8a57aea8d69 100644 --- a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -15,16 +15,20 @@ import semmle.python.dataflow.new.DataFlow import semmle.python.Concepts import experimental.semmle.python.Concepts -from HeaderDeclaration headerWrite, False f, None n +from Expr cookieExpr, False f, None n where - exists(StrConst headerName, StrConst headerValue | + exists(HeaderDeclaration headerWrite, StrConst headerName, StrConst headerValue | headerName.getText() = "Set-Cookie" and DataFlow::exprNode(headerName).(DataFlow::LocalSourceNode).flowsTo(headerWrite.getNameArg()) and not headerValue.getText().regexpMatch(".*; *Secure;.*") and - DataFlow::exprNode(headerValue).(DataFlow::LocalSourceNode).flowsTo(headerWrite.getValueArg()) + DataFlow::exprNode(headerValue).(DataFlow::LocalSourceNode).flowsTo(headerWrite.getValueArg()) and + cookieExpr = headerWrite.asExpr() ) or - [DataFlow::exprNode(f), DataFlow::exprNode(n)] - .(DataFlow::LocalSourceNode) - .flowsTo(headerWrite.(DataFlow::CallCfgNode).getArgByName("secure")) -select headerWrite, "Cookie is added to response without the 'secure' flag being set." + exists(ExperimentalHTTP::CookieWrite cookieWrite | + [DataFlow::exprNode(f), DataFlow::exprNode(n)] + .(DataFlow::LocalSourceNode) + .flowsTo(cookieWrite.(DataFlow::CallCfgNode).getArgByName("secure")) and + cookieExpr = cookieWrite.asExpr() + ) +select cookieExpr, "Cookie is added to response without the 'secure' flag being set." diff --git a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll index 9c66d9a4601..2a2cc68fe84 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll @@ -81,4 +81,20 @@ module ExperimentalFlask { override DataFlow::Node getValueArg() { result.asExpr() = item.getValue() } } + + class DjangoSetCookieCall extends DataFlow::CallCfgNode, ExperimentalHTTP::CookieWrite::Range { + DjangoSetCookieCall() { + this = + [Flask::Response::classRef(), flaskMakeResponse()] + .getReturn() + .getMember("set_cookie") + .getACall() + } + + override DataFlow::Node getHeaderArg() { none() } + + override DataFlow::Node getNameArg() { result = this.getArg(0) } + + override DataFlow::Node getValueArg() { result = this.getArg(1) } + } } diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py index 877231f8f14..02752d32f99 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py @@ -9,5 +9,5 @@ def django_response(request): def django_response(request): resp = django.http.HttpResponse() - resp.set_cookie("name", "value") + resp.set_cookie("name", "value", secure=False) return resp From c8a7f48d6efa57bd9907086742b0860a4d3bb4a0 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Sun, 25 Jul 2021 18:18:38 +0200 Subject: [PATCH 006/171] Add `.expected` --- .../query-tests/Security/CWE-614/InsecureCookie.expected | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected b/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected new file mode 100644 index 00000000000..5c157a11976 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected @@ -0,0 +1,6 @@ +| django_bad.py:6:5:6:49 | Attribute() | Cookie is added to response without the 'secure' flag being set. | +| django_bad.py:12:5:12:50 | Attribute() | Cookie is added to response without the 'secure' flag being set. | +| flask_bad.py:9:5:9:56 | Attribute() | Cookie is added to response without the 'secure' flag being set. | +| flask_bad.py:16:5:16:55 | Attribute() | Cookie is added to response without the 'secure' flag being set. | +| flask_bad.py:23:5:23:30 | Subscript | Cookie is added to response without the 'secure' flag being set. | +| flask_bad.py:30:5:30:30 | Subscript | Cookie is added to response without the 'secure' flag being set. | From 54ed25a925caf2e05e2c5189dc3c0e4f99d463d9 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Sun, 25 Jul 2021 18:21:16 +0200 Subject: [PATCH 007/171] Change `False` and `None` scopes --- python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index 8a57aea8d69..02b1280abab 100644 --- a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -15,7 +15,7 @@ import semmle.python.dataflow.new.DataFlow import semmle.python.Concepts import experimental.semmle.python.Concepts -from Expr cookieExpr, False f, None n +from Expr cookieExpr where exists(HeaderDeclaration headerWrite, StrConst headerName, StrConst headerValue | headerName.getText() = "Set-Cookie" and @@ -25,7 +25,7 @@ where cookieExpr = headerWrite.asExpr() ) or - exists(ExperimentalHTTP::CookieWrite cookieWrite | + exists(ExperimentalHTTP::CookieWrite cookieWrite, False f, None n | [DataFlow::exprNode(f), DataFlow::exprNode(n)] .(DataFlow::LocalSourceNode) .flowsTo(cookieWrite.(DataFlow::CallCfgNode).getArgByName("secure")) and From 48c3c3d8a8df6cf3d0a65d00fe400aae1537314a Mon Sep 17 00:00:00 2001 From: jorgectf Date: Wed, 27 Oct 2021 21:00:50 +0200 Subject: [PATCH 008/171] Broaden scope --- .../Security/CWE-614/InsecureCookie.ql | 25 +++++------- .../experimental/semmle/python/Concepts.qll | 39 +++++++++---------- .../semmle/python/CookieHeader.qll | 26 +++++++++++++ .../semmle/python/frameworks/Django.qll | 19 ++++++--- .../semmle/python/frameworks/Flask.qll | 20 +++++++--- 5 files changed, 82 insertions(+), 47 deletions(-) create mode 100644 python/ql/src/experimental/semmle/python/CookieHeader.qll diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index 02b1280abab..bf0ff22d45e 100644 --- a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -12,23 +12,16 @@ // determine precision above import python import semmle.python.dataflow.new.DataFlow -import semmle.python.Concepts import experimental.semmle.python.Concepts -from Expr cookieExpr +from Cookie cookie, string alert where - exists(HeaderDeclaration headerWrite, StrConst headerName, StrConst headerValue | - headerName.getText() = "Set-Cookie" and - DataFlow::exprNode(headerName).(DataFlow::LocalSourceNode).flowsTo(headerWrite.getNameArg()) and - not headerValue.getText().regexpMatch(".*; *Secure;.*") and - DataFlow::exprNode(headerValue).(DataFlow::LocalSourceNode).flowsTo(headerWrite.getValueArg()) and - cookieExpr = headerWrite.asExpr() - ) + cookie.isSecure() and + alert = "secure" or - exists(ExperimentalHTTP::CookieWrite cookieWrite, False f, None n | - [DataFlow::exprNode(f), DataFlow::exprNode(n)] - .(DataFlow::LocalSourceNode) - .flowsTo(cookieWrite.(DataFlow::CallCfgNode).getArgByName("secure")) and - cookieExpr = cookieWrite.asExpr() - ) -select cookieExpr, "Cookie is added to response without the 'secure' flag being set." + not cookie.isHttpOnly() and + alert = "httponly" + or + cookie.isSameSite() and + alert = "samesite" +select cookie, "Cookie is added without the ", alert, " flag properly set." diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll index 9da35b854a5..b6a15cb025b 100644 --- a/python/ql/src/experimental/semmle/python/Concepts.qll +++ b/python/ql/src/experimental/semmle/python/Concepts.qll @@ -301,54 +301,51 @@ class HeaderDeclaration extends DataFlow::Node { * A data-flow node that sets a cookie in an HTTP response. * * Extend this class to refine existing API models. If you want to model new APIs, - * extend `HTTP::CookieWrite::Range` instead. + * extend `Cookie::Range` instead. */ -class CookieWrite extends DataFlow::Node { - CookieWrite::Range range; +class Cookie extends DataFlow::Node { + Cookie::Range range; - CookieWrite() { this = range } + Cookie() { this = range } /** - * Gets the argument, if any, specifying the raw cookie header. + * Holds if this cookie is secure. */ - DataFlow::Node getHeaderArg() { result = range.getHeaderArg() } + predicate isSecure() { range.isSecure() } /** - * Gets the argument, if any, specifying the cookie name. + * Holds if this cookie is HttpOnly. */ - DataFlow::Node getNameArg() { result = range.getNameArg() } + predicate isHttpOnly() { range.isHttpOnly() } /** - * Gets the argument, if any, specifying the cookie value. + * Holds if the cookie is SameSite */ - DataFlow::Node getValueArg() { result = range.getValueArg() } + predicate isSameSite() { range.isSameSite() } } /** Provides a class for modeling new cookie writes on HTTP responses. */ -module CookieWrite { +module Cookie { /** * A data-flow node that sets a cookie in an HTTP response. * - * Note: we don't require that this redirect must be sent to a client (a kind of - * "if a tree falls in a forest and nobody hears it" situation). - * * Extend this class to model new APIs. If you want to refine existing API models, - * extend `HttpResponse` instead. + * extend `Cookie` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets the argument, if any, specifying the raw cookie header. + * Holds if this cookie is secure. */ - abstract DataFlow::Node getHeaderArg(); + abstract predicate isSecure(); /** - * Gets the argument, if any, specifying the cookie name. + * Holds if this cookie is HttpOnly. */ - abstract DataFlow::Node getNameArg(); + abstract predicate isHttpOnly(); /** - * Gets the argument, if any, specifying the cookie value. + * Holds if the cookie is SameSite. */ - abstract DataFlow::Node getValueArg(); + abstract predicate isSameSite(); } } diff --git a/python/ql/src/experimental/semmle/python/CookieHeader.qll b/python/ql/src/experimental/semmle/python/CookieHeader.qll new file mode 100644 index 00000000000..610fa311310 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/CookieHeader.qll @@ -0,0 +1,26 @@ +/** + * Temporary: provides a class to extend current cookies to header declarations + */ + +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking +import experimental.semmle.python.Concepts + +class CookieHeader extends HeaderDeclaration, Cookie::Range { + CookieHeader() { + this instanceof HeaderDeclaration and this.getNameArg().asExpr().(Str_).getS() = "Set-Cookie" + } + + override predicate isSecure() { + this.getValueArg().asExpr().(Str_).getS().regexpMatch(".*; *Secure;.*") + } + + override predicate isHttpOnly() { + this.getValueArg().asExpr().(Str_).getS().regexpMatch(".*; *HttpOnly;.*") + } + + override predicate isSameSite() { + this.getValueArg().asExpr().(Str_).getS().regexpMatch(".*; *SameSite=(Strict|Lax);.*") + } +} diff --git a/python/ql/src/experimental/semmle/python/frameworks/Django.qll b/python/ql/src/experimental/semmle/python/frameworks/Django.qll index 1a3c5c1cf10..fb6762d3dc3 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Django.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Django.qll @@ -87,15 +87,24 @@ private module PrivateDjango { override DataFlow::Node getValueArg() { result = headerInput } } - class DjangoSetCookieCall extends DataFlow::CallCfgNode, - ExperimentalHTTP::CookieWrite::Range { + class DjangoSetCookieCall extends DataFlow::CallCfgNode, Cookie::Range { DjangoSetCookieCall() { this = baseClassRef().getMember("set_cookie").getACall() } - override DataFlow::Node getHeaderArg() { none() } + override predicate isSecure() { + DataFlow::exprNode(any(True t)) + .(DataFlow::LocalSourceNode) + .flowsTo(this.getArgByName("secure")) + } - override DataFlow::Node getNameArg() { result = this.getArg(0) } + override predicate isHttpOnly() { + DataFlow::exprNode(any(True t)) + .(DataFlow::LocalSourceNode) + .flowsTo(this.getArgByName("httponly")) + } - override DataFlow::Node getValueArg() { result = this.getArg(1) } + override predicate isSameSite() { + this.getArgByName("samesite").asExpr().(Str_).getS() in ["Strict", "Lax"] + } } } } diff --git a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll index 2a2cc68fe84..614e0738bcc 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll @@ -82,8 +82,8 @@ module ExperimentalFlask { override DataFlow::Node getValueArg() { result.asExpr() = item.getValue() } } - class DjangoSetCookieCall extends DataFlow::CallCfgNode, ExperimentalHTTP::CookieWrite::Range { - DjangoSetCookieCall() { + class FlaskSetCookieCall extends DataFlow::CallCfgNode, Cookie::Range { + FlaskSetCookieCall() { this = [Flask::Response::classRef(), flaskMakeResponse()] .getReturn() @@ -91,10 +91,20 @@ module ExperimentalFlask { .getACall() } - override DataFlow::Node getHeaderArg() { none() } + override predicate isSecure() { + DataFlow::exprNode(any(True t)) + .(DataFlow::LocalSourceNode) + .flowsTo(this.getArgByName("secure")) + } - override DataFlow::Node getNameArg() { result = this.getArg(0) } + override predicate isHttpOnly() { + DataFlow::exprNode(any(True t)) + .(DataFlow::LocalSourceNode) + .flowsTo(this.getArgByName("httponly")) + } - override DataFlow::Node getValueArg() { result = this.getArg(1) } + override predicate isSameSite() { + this.getArgByName("samesite").asExpr().(Str_).getS() in ["Strict", "Lax"] + } } } From 0f2b81e0d2ae3ed0b56763870d0f7787696ae54e Mon Sep 17 00:00:00 2001 From: jorgectf Date: Thu, 28 Oct 2021 09:24:47 +0200 Subject: [PATCH 009/171] Polish tests --- .../query-tests/Security/CWE-614/django_bad.py | 6 ++++-- .../query-tests/Security/CWE-614/django_good.py | 5 +++-- .../query-tests/Security/CWE-614/flask_bad.py | 12 +++--------- .../query-tests/Security/CWE-614/flask_good.py | 7 ++++--- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py index 02752d32f99..340291a6b9c 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py @@ -3,11 +3,13 @@ import django.http def django_response(request): resp = django.http.HttpResponse() - resp.set_cookie("name", "value", secure=None) + resp.set_cookie("name", "value", secure=False, + httponly=False, samesite='None') return resp def django_response(request): resp = django.http.HttpResponse() - resp.set_cookie("name", "value", secure=False) + resp.set_cookie("name", "value", secure=False, + httponly=False, samesite='None') return resp diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/django_good.py b/python/ql/test/experimental/query-tests/Security/CWE-614/django_good.py index ebf16236de2..7476971cbb5 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/django_good.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/django_good.py @@ -3,13 +3,14 @@ import django.http def django_response(request): resp = django.http.HttpResponse() - resp['Set-Cookie'] = "name=value; Secure;" + resp['Set-Cookie'] = "name=value; Secure; HttpOnly; SameSite=Lax;" return resp def django_response(request): resp = django.http.HttpResponse() - resp.set_cookie("name", "value", secure=True) + resp.set_cookie("name", "value", secure=True, + httponly=True, samesite='Lax') return resp diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py index 7c7d6e8acd0..f32d28a6f65 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py @@ -6,14 +6,8 @@ app = Flask(__name__) @app.route("/false") def false(): resp = make_response() - resp.set_cookie("name", value="value", secure=False) - return resp - - -@app.route("/none") -def none(): - resp = make_response() - resp.set_cookie("name", value="value", secure=None) + resp.set_cookie("name", value="value", secure=False, + httponly=False, samesite='None') return resp @@ -27,7 +21,7 @@ def flask_Response(): @app.route("/flask_make_response") def flask_make_response(): resp = make_response("hello") - resp.headers['Set-Cookie'] = "name=value;" + resp.headers['Set-Cookie'] = "name=value; SameSite=None;" return resp # if __name__ == "__main__": diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py index 05ee3f28657..5b9f83e1a63 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py @@ -6,21 +6,22 @@ app = Flask(__name__) @app.route("/true") def true(): resp = make_response() - resp.set_cookie("name", value="value", secure=True) + resp.set_cookie("name", value="value", secure=True, + httponly=True, samesite='Lax') return resp @app.route("/flask_Response") def flask_Response(): resp = Response() - resp.headers['Set-Cookie'] = "name=value; Secure;" + resp.headers['Set-Cookie'] = "name=value; Secure; HttpOnly; SameSite=Lax;" return resp @app.route("/flask_make_response") def flask_make_response(): resp = make_response("hello") - resp.headers['Set-Cookie'] = "name=value; Secure;" + resp.headers['Set-Cookie'] = "name=value; Secure; HttpOnly; SameSite=Lax;" return resp From 5dc1ad6f8ab9e3c656e5faac12e5b918a54ac730 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Thu, 28 Oct 2021 09:25:47 +0200 Subject: [PATCH 010/171] Polish `.ql` --- .../src/experimental/Security/CWE-614/InsecureCookie.qhelp | 2 +- .../ql/src/experimental/Security/CWE-614/InsecureCookie.ql | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp index ab5e3031629..97df2e49e13 100644 --- a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp @@ -23,4 +23,4 @@ secure flag and the second adds the secure flag in the cookie's raw value.

  • PortSwigger: TLS cookie without secure flag set.
  • - \ No newline at end of file + diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index bf0ff22d45e..ee22243e5c3 100644 --- a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -13,15 +13,16 @@ import python import semmle.python.dataflow.new.DataFlow import experimental.semmle.python.Concepts +import experimental.semmle.python.CookieHeader from Cookie cookie, string alert where - cookie.isSecure() and + not cookie.isSecure() and alert = "secure" or not cookie.isHttpOnly() and alert = "httponly" or - cookie.isSameSite() and + not cookie.isSameSite() and alert = "samesite" select cookie, "Cookie is added without the ", alert, " flag properly set." From 129edd605ea7092fa3d309b3f0e322f983d69b3e Mon Sep 17 00:00:00 2001 From: jorgectf Date: Thu, 28 Oct 2021 09:25:56 +0200 Subject: [PATCH 011/171] Update `.expected` --- .../Security/CWE-614/InsecureCookie.expected | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected b/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected index 5c157a11976..a04ad9cdafe 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected @@ -1,6 +1,21 @@ -| django_bad.py:6:5:6:49 | Attribute() | Cookie is added to response without the 'secure' flag being set. | -| django_bad.py:12:5:12:50 | Attribute() | Cookie is added to response without the 'secure' flag being set. | -| flask_bad.py:9:5:9:56 | Attribute() | Cookie is added to response without the 'secure' flag being set. | -| flask_bad.py:16:5:16:55 | Attribute() | Cookie is added to response without the 'secure' flag being set. | -| flask_bad.py:23:5:23:30 | Subscript | Cookie is added to response without the 'secure' flag being set. | -| flask_bad.py:30:5:30:30 | Subscript | Cookie is added to response without the 'secure' flag being set. | +| django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | +| django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | +| django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | +| django_bad.py:13:5:14:52 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | +| django_bad.py:13:5:14:52 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | +| django_bad.py:13:5:14:52 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | +| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | +| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | +| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | +| flask_bad.py:9:5:10:52 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | +| flask_bad.py:9:5:10:52 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | +| flask_bad.py:9:5:10:52 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | +| flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the | httponly | flag properly set. | +| flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the | samesite | flag properly set. | +| flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the | secure | flag properly set. | +| flask_bad.py:24:5:24:30 | ControlFlowNode for Subscript | Cookie is added without the | httponly | flag properly set. | +| flask_bad.py:24:5:24:30 | ControlFlowNode for Subscript | Cookie is added without the | samesite | flag properly set. | +| flask_bad.py:24:5:24:30 | ControlFlowNode for Subscript | Cookie is added without the | secure | flag properly set. | +| flask_good.py:31:5:31:57 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | +| flask_good.py:31:5:31:57 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | +| flask_good.py:31:5:31:57 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | From cf9e9f9dd4b0ffc99d169d910e914cef78725bae Mon Sep 17 00:00:00 2001 From: jorgectf Date: Thu, 28 Oct 2021 10:28:45 +0200 Subject: [PATCH 012/171] Add cookie injection query missing proper tests --- .../Security/CWE-614/CookieInjection.ql | 28 +++++++++++++ .../experimental/semmle/python/Concepts.qll | 20 ++++++++++ .../semmle/python/CookieHeader.qll | 18 +++++++-- .../semmle/python/frameworks/Django.qll | 4 ++ .../semmle/python/frameworks/Flask.qll | 4 ++ .../security/injection/CookieInjection.qll | 40 +++++++++++++++++++ .../query-tests/Security/CWE-614/flask_bad.py | 2 +- 7 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 python/ql/src/experimental/Security/CWE-614/CookieInjection.ql create mode 100644 python/ql/src/experimental/semmle/python/security/injection/CookieInjection.qll diff --git a/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql b/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql new file mode 100644 index 00000000000..e97ff962919 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql @@ -0,0 +1,28 @@ +/** + * @name Failure to use secure cookies + * @description Insecure cookies may be sent in cleartext, which makes them vulnerable to + * interception. + * @kind problem + * @problem.severity error + * @id py/insecure-cookie + * @tags security + * external/cwe/cwe-614 + */ + +// determine precision above +import python +import semmle.python.dataflow.new.DataFlow +import experimental.semmle.python.Concepts +import experimental.semmle.python.CookieHeader +import experimental.semmle.python.security.injection.CookieInjection + +from + CookieInjectionFlowConfig config, DataFlow::PathNode source, DataFlow::PathNode sink, + string insecure +where + config.hasFlowPath(source, sink) and + if exists(sink.getNode().(CookieSink)) + then insecure = "and it's " + sink.getNode().(CookieSink).getFlag() + " flag is not properly set" + else insecure = "" +select sink.getNode(), "Cookie is constructed from a", source.getNode(), "user-supplied input", + insecure diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll index b6a15cb025b..64aa755d9cf 100644 --- a/python/ql/src/experimental/semmle/python/Concepts.qll +++ b/python/ql/src/experimental/semmle/python/Concepts.qll @@ -322,6 +322,16 @@ class Cookie extends DataFlow::Node { * Holds if the cookie is SameSite */ predicate isSameSite() { range.isSameSite() } + + /** + * Gets the argument containing the header name. + */ + DataFlow::Node getName() { result = range.getName() } + + /** + * Gets the argument containing the header value. + */ + DataFlow::Node getValue() { result = range.getValue() } } /** Provides a class for modeling new cookie writes on HTTP responses. */ @@ -347,5 +357,15 @@ module Cookie { * Holds if the cookie is SameSite. */ abstract predicate isSameSite(); + + /** + * Gets the argument containing the header name. + */ + abstract DataFlow::Node getName(); + + /** + * Gets the argument containing the header value. + */ + abstract DataFlow::Node getValue(); } } diff --git a/python/ql/src/experimental/semmle/python/CookieHeader.qll b/python/ql/src/experimental/semmle/python/CookieHeader.qll index 610fa311310..c7779aadd80 100644 --- a/python/ql/src/experimental/semmle/python/CookieHeader.qll +++ b/python/ql/src/experimental/semmle/python/CookieHeader.qll @@ -9,18 +9,28 @@ import experimental.semmle.python.Concepts class CookieHeader extends HeaderDeclaration, Cookie::Range { CookieHeader() { - this instanceof HeaderDeclaration and this.getNameArg().asExpr().(Str_).getS() = "Set-Cookie" + this instanceof HeaderDeclaration and + this.(HeaderDeclaration).getNameArg().asExpr().(Str_).getS() = "Set-Cookie" } override predicate isSecure() { - this.getValueArg().asExpr().(Str_).getS().regexpMatch(".*; *Secure;.*") + this.(HeaderDeclaration).getValueArg().asExpr().(Str_).getS().regexpMatch(".*; *Secure;.*") } override predicate isHttpOnly() { - this.getValueArg().asExpr().(Str_).getS().regexpMatch(".*; *HttpOnly;.*") + this.(HeaderDeclaration).getValueArg().asExpr().(Str_).getS().regexpMatch(".*; *HttpOnly;.*") } override predicate isSameSite() { - this.getValueArg().asExpr().(Str_).getS().regexpMatch(".*; *SameSite=(Strict|Lax);.*") + this.(HeaderDeclaration) + .getValueArg() + .asExpr() + .(Str_) + .getS() + .regexpMatch(".*; *SameSite=(Strict|Lax);.*") } + + override DataFlow::Node getName() { result = this.(HeaderDeclaration).getValueArg() } + + override DataFlow::Node getValue() { result = this.(HeaderDeclaration).getValueArg() } } diff --git a/python/ql/src/experimental/semmle/python/frameworks/Django.qll b/python/ql/src/experimental/semmle/python/frameworks/Django.qll index fb6762d3dc3..ba99ddaa800 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Django.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Django.qll @@ -90,6 +90,10 @@ private module PrivateDjango { class DjangoSetCookieCall extends DataFlow::CallCfgNode, Cookie::Range { DjangoSetCookieCall() { this = baseClassRef().getMember("set_cookie").getACall() } + override DataFlow::Node getName() { result = this.getArg(0) } + + override DataFlow::Node getValue() { result = this.getArgByName("value") } + override predicate isSecure() { DataFlow::exprNode(any(True t)) .(DataFlow::LocalSourceNode) diff --git a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll index 614e0738bcc..b93e6713846 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll @@ -91,6 +91,10 @@ module ExperimentalFlask { .getACall() } + override DataFlow::Node getName() { result = this.getArg(0) } + + override DataFlow::Node getValue() { result = this.getArgByName("value") } + override predicate isSecure() { DataFlow::exprNode(any(True t)) .(DataFlow::LocalSourceNode) diff --git a/python/ql/src/experimental/semmle/python/security/injection/CookieInjection.qll b/python/ql/src/experimental/semmle/python/security/injection/CookieInjection.qll new file mode 100644 index 00000000000..41f7c2af7d3 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/security/injection/CookieInjection.qll @@ -0,0 +1,40 @@ +import python +import experimental.semmle.python.Concepts +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking +import semmle.python.dataflow.new.RemoteFlowSources + +class CookieSink extends DataFlow::Node { + string flag; + + CookieSink() { + exists(Cookie cookie | + this in [cookie.getName(), cookie.getValue()] and + ( + not cookie.isSecure() and + flag = "secure" + or + not cookie.isHttpOnly() and + flag = "httponly" + or + not cookie.isSameSite() and + flag = "samesite" + ) + ) + } + + string getFlag() { result = flag } +} + +/** + * A taint-tracking configuration for detecting Cookie injections. + */ +class CookieInjectionFlowConfig extends TaintTracking::Configuration { + CookieInjectionFlowConfig() { this = "CookieInjectionFlowConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { + exists(Cookie c | sink in [c.getName(), c.getValue()]) + } +} diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py index f32d28a6f65..fc0177e3012 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py @@ -6,7 +6,7 @@ app = Flask(__name__) @app.route("/false") def false(): resp = make_response() - resp.set_cookie("name", value="value", secure=False, + resp.set_cookie(request.args["name"], value=request.args["value"], secure=False, httponly=False, samesite='None') return resp From 4cb78ac654981ba68960bb13352da99b9590bc1c Mon Sep 17 00:00:00 2001 From: jorgectf Date: Fri, 5 Nov 2021 20:08:37 +0100 Subject: [PATCH 013/171] Fix typo --- python/ql/src/experimental/Security/CWE-614/CookieInjection.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql b/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql index e97ff962919..b4a880e9a58 100644 --- a/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql +++ b/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql @@ -22,7 +22,7 @@ from where config.hasFlowPath(source, sink) and if exists(sink.getNode().(CookieSink)) - then insecure = "and it's " + sink.getNode().(CookieSink).getFlag() + " flag is not properly set" + then insecure = "and its " + sink.getNode().(CookieSink).getFlag() + " flag is not properly set" else insecure = "" select sink.getNode(), "Cookie is constructed from a", source.getNode(), "user-supplied input", insecure From d7a79469e62e8cc98e2ccff0b6f53b2f43a0058e Mon Sep 17 00:00:00 2001 From: jorgectf Date: Fri, 5 Nov 2021 20:08:52 +0100 Subject: [PATCH 014/171] Improve tests --- .../Security/CWE-614/django_bad.py | 17 ++++++++++++-- .../query-tests/Security/CWE-614/flask_bad.py | 23 +++++++++++++------ .../Security/CWE-614/flask_good.py | 7 ------ 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py index 340291a6b9c..6f1916930e5 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py @@ -8,8 +8,21 @@ def django_response(request): return resp +def django_response(): + response = django.http.HttpResponse() + response['Set-Cookie'] = "name=value; SameSite=None;" + return response + + def django_response(request): resp = django.http.HttpResponse() - resp.set_cookie("name", "value", secure=False, - httponly=False, samesite='None') + resp.set_cookie(django.http.request.GET.get("name"), + django.http.request.GET.get("value"), + secure=False, httponly=False, samesite='None') return resp + + +def django_response(): + response = django.http.HttpResponse() + response['Set-Cookie'] = f"{django.http.request.GET.get('name')}={django.http.request.GET.get('value')}; SameSite=None;" + return response diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py index fc0177e3012..740070a7b53 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py @@ -3,6 +3,21 @@ from flask import Flask, request, make_response, Response app = Flask(__name__) +@app.route("/false") +def false(): + resp = make_response() + resp.set_cookie("name", value="value", secure=False, + httponly=False, samesite='None') + return resp + + +@app.route("/flask_Response") +def flask_Response(): + resp = Response() + resp.headers['Set-Cookie'] = "name=value; SameSite=None;" + return resp + + @app.route("/false") def false(): resp = make_response() @@ -14,15 +29,9 @@ def false(): @app.route("/flask_Response") def flask_Response(): resp = Response() - resp.headers['Set-Cookie'] = "name=value;" + resp.headers['Set-Cookie'] = f"{request.args['name']}={request.args['value']}; SameSite=None;" return resp -@app.route("/flask_make_response") -def flask_make_response(): - resp = make_response("hello") - resp.headers['Set-Cookie'] = "name=value; SameSite=None;" - return resp - # if __name__ == "__main__": # app.run(debug=True) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py index 5b9f83e1a63..724f8de8289 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py @@ -18,13 +18,6 @@ def flask_Response(): return resp -@app.route("/flask_make_response") -def flask_make_response(): - resp = make_response("hello") - resp.headers['Set-Cookie'] = "name=value; Secure; HttpOnly; SameSite=Lax;" - return resp - - def indeterminate(secure): resp = make_response() resp.set_cookie("name", value="value", secure=secure) From b3258ce20f64abf22d72282ed28bcaffeca007db Mon Sep 17 00:00:00 2001 From: jorgectf Date: Fri, 5 Nov 2021 20:12:05 +0100 Subject: [PATCH 015/171] Add `CookieInjection` sample and `.qhelp` --- .../Security/CWE-614/CookieInjection.py | 16 +++++++++++ .../Security/CWE-614/CookieInjection.qhelp | 28 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 python/ql/src/experimental/Security/CWE-614/CookieInjection.py create mode 100644 python/ql/src/experimental/Security/CWE-614/CookieInjection.qhelp diff --git a/python/ql/src/experimental/Security/CWE-614/CookieInjection.py b/python/ql/src/experimental/Security/CWE-614/CookieInjection.py new file mode 100644 index 00000000000..55d211bafc1 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-614/CookieInjection.py @@ -0,0 +1,16 @@ +from flask import request, make_response + + +@app.route("/1") +def true(): + resp = make_response() + resp.set_cookie(request.args["name"], + value=request.args["name"]) + return resp + + +@app.route("/2") +def flask_make_response(): + resp = make_response("hello") + resp.headers['Set-Cookie'] = f"{request.args['name']}={request.args['name']};" + return resp diff --git a/python/ql/src/experimental/Security/CWE-614/CookieInjection.qhelp b/python/ql/src/experimental/Security/CWE-614/CookieInjection.qhelp new file mode 100644 index 00000000000..4b5ec11726c --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-614/CookieInjection.qhelp @@ -0,0 +1,28 @@ + + + + +

    Constructing cookies from user input may allow an attacker to perform a Cookie Poisoning attack. +It is possible, however, to perform other parameter-like attacks through cookie poisoning techniques, +such as SQL Injection, Directory Traversal, or Stealth Commanding, etc. Additionally, +cookie injection may relate to attempts to perform Access of Administrative Interface. +

    +
    + + +

    Do not use raw user input to construct cookies.

    +
    + + +

    This example shows two ways of adding a cookie to a Flask response. The first way uses set_cookie's +and the second sets a cookie's raw value through a header, both using user-supplied input.

    + +
    + + +
  • Imperva: Cookie injection.
  • +
    + +
    From cf47e8eb9ce3d6a33e38c905f70c06c6dbea754e Mon Sep 17 00:00:00 2001 From: jorgectf Date: Fri, 5 Nov 2021 20:12:35 +0100 Subject: [PATCH 016/171] Fix endpoints' naming --- .../src/experimental/Security/CWE-614/InsecureCookie.py | 6 +++--- .../query-tests/Security/CWE-614/flask_bad.py | 8 ++++---- .../query-tests/Security/CWE-614/flask_good.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.py b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.py index 54bbeff7d12..4087830f7eb 100644 --- a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.py +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.py @@ -1,15 +1,15 @@ from flask import Flask, request, make_response, Response -@app.route("/true") +@app.route("/1") def true(): resp = make_response() resp.set_cookie("name", value="value", secure=True) return resp -@app.route("/flask_make_response") +@app.route("/2") def flask_make_response(): resp = make_response("hello") resp.headers['Set-Cookie'] = "name=value; Secure;" - return resp \ No newline at end of file + return resp diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py index 740070a7b53..431df5eb4d8 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_bad.py @@ -3,7 +3,7 @@ from flask import Flask, request, make_response, Response app = Flask(__name__) -@app.route("/false") +@app.route("/1") def false(): resp = make_response() resp.set_cookie("name", value="value", secure=False, @@ -11,14 +11,14 @@ def false(): return resp -@app.route("/flask_Response") +@app.route("/2") def flask_Response(): resp = Response() resp.headers['Set-Cookie'] = "name=value; SameSite=None;" return resp -@app.route("/false") +@app.route("/3") def false(): resp = make_response() resp.set_cookie(request.args["name"], value=request.args["value"], secure=False, @@ -26,7 +26,7 @@ def false(): return resp -@app.route("/flask_Response") +@app.route("/4") def flask_Response(): resp = Response() resp.headers['Set-Cookie'] = f"{request.args['name']}={request.args['value']}; SameSite=None;" diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py index 724f8de8289..4cb23bd84b3 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/flask_good.py @@ -3,7 +3,7 @@ from flask import Flask, request, make_response, Response app = Flask(__name__) -@app.route("/true") +@app.route("/1") def true(): resp = make_response() resp.set_cookie("name", value="value", secure=True, @@ -11,7 +11,7 @@ def true(): return resp -@app.route("/flask_Response") +@app.route("/2") def flask_Response(): resp = Response() resp.headers['Set-Cookie'] = "name=value; Secure; HttpOnly; SameSite=Lax;" From a420e6e18dae60e7013ad314d0df8e78eb840c45 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Fri, 5 Nov 2021 20:12:56 +0100 Subject: [PATCH 017/171] Add `CookieInjection.qlref` --- .../query-tests/Security/CWE-614/CookieInjection.qlref | 1 + 1 file changed, 1 insertion(+) create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.qlref diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.qlref b/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.qlref new file mode 100644 index 00000000000..5710a3322de --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-614/CookieInjection.ql From 86aac7c215408e41389866da890842052a39fcfd Mon Sep 17 00:00:00 2001 From: jorgectf Date: Fri, 5 Nov 2021 20:13:12 +0100 Subject: [PATCH 018/171] Add/Update `.expected` files. --- .../Security/CWE-614/CookieInjection.expected | 24 +++++++++++++++++ .../Security/CWE-614/InsecureCookie.expected | 27 ++++++++++++------- 2 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected new file mode 100644 index 00000000000..fc368c95323 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected @@ -0,0 +1,24 @@ +| django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | and its httponly flag is not properly set | +| django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | and its samesite flag is not properly set | +| django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | and its secure flag is not properly set | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | and its httponly flag is not properly set | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | and its samesite flag is not properly set | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | and its secure flag is not properly set | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input | and its httponly flag is not properly set | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input | and its samesite flag is not properly set | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input | and its secure flag is not properly set | +| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its httponly flag is not properly set | +| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its samesite flag is not properly set | +| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its secure flag is not properly set | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its httponly flag is not properly set | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its samesite flag is not properly set | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its secure flag is not properly set | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:49:24:55 | ControlFlowNode for request | user-supplied input | and its httponly flag is not properly set | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:49:24:55 | ControlFlowNode for request | user-supplied input | and its samesite flag is not properly set | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:49:24:55 | ControlFlowNode for request | user-supplied input | and its secure flag is not properly set | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:37:32:43 | ControlFlowNode for request | user-supplied input | and its httponly flag is not properly set | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:37:32:43 | ControlFlowNode for request | user-supplied input | and its samesite flag is not properly set | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:37:32:43 | ControlFlowNode for request | user-supplied input | and its secure flag is not properly set | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:60:32:66 | ControlFlowNode for request | user-supplied input | and its httponly flag is not properly set | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:60:32:66 | ControlFlowNode for request | user-supplied input | and its samesite flag is not properly set | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:60:32:66 | ControlFlowNode for request | user-supplied input | and its secure flag is not properly set | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected b/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected index a04ad9cdafe..1ece5048db8 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected @@ -1,9 +1,15 @@ | django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | | django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | | django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | -| django_bad.py:13:5:14:52 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | -| django_bad.py:13:5:14:52 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | -| django_bad.py:13:5:14:52 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | +| django_bad.py:13:5:13:26 | ControlFlowNode for Subscript | Cookie is added without the | httponly | flag properly set. | +| django_bad.py:13:5:13:26 | ControlFlowNode for Subscript | Cookie is added without the | samesite | flag properly set. | +| django_bad.py:13:5:13:26 | ControlFlowNode for Subscript | Cookie is added without the | secure | flag properly set. | +| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | +| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | +| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | +| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the | httponly | flag properly set. | +| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the | samesite | flag properly set. | +| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the | secure | flag properly set. | | django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | | django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | | django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | @@ -13,9 +19,12 @@ | flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the | httponly | flag properly set. | | flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the | samesite | flag properly set. | | flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the | secure | flag properly set. | -| flask_bad.py:24:5:24:30 | ControlFlowNode for Subscript | Cookie is added without the | httponly | flag properly set. | -| flask_bad.py:24:5:24:30 | ControlFlowNode for Subscript | Cookie is added without the | samesite | flag properly set. | -| flask_bad.py:24:5:24:30 | ControlFlowNode for Subscript | Cookie is added without the | secure | flag properly set. | -| flask_good.py:31:5:31:57 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | -| flask_good.py:31:5:31:57 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | -| flask_good.py:31:5:31:57 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | +| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | +| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | +| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | +| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the | httponly | flag properly set. | +| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the | samesite | flag properly set. | +| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the | secure | flag properly set. | +| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | +| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | +| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | From 83e3de1fed2ccb90bc16325a4ba940a8feeb3253 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Fri, 5 Nov 2021 21:05:33 +0100 Subject: [PATCH 019/171] Polish documentation. --- .../Security/CWE-614/CookieInjection.ql | 7 +++---- .../Security/CWE-614/InsecureCookie.qhelp | 9 +++++++-- .../semmle/python/CookieHeader.qll | 19 ++++++++++++++++++ .../semmle/python/frameworks/Django.qll | 19 ++++++++++++++++++ .../semmle/python/frameworks/Flask.qll | 20 +++++++++++++++++++ 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql b/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql index b4a880e9a58..8f7ef99789b 100644 --- a/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql +++ b/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql @@ -1,10 +1,9 @@ /** - * @name Failure to use secure cookies - * @description Insecure cookies may be sent in cleartext, which makes them vulnerable to - * interception. + * @name Construction of a cookie using user-supplied input. + * @description Constructing cookies from user input may allow an attacker to perform a Cookie Poisoning attack. * @kind problem * @problem.severity error - * @id py/insecure-cookie + * @id py/cookie-injection * @tags security * external/cwe/cwe-614 */ diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp index 97df2e49e13..c76ab17954a 100644 --- a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp @@ -4,12 +4,17 @@ -

    Failing to set the 'secure' flag on a cookie can cause it to be sent in cleartext. -This makes it easier for an attacker to intercept.

    +

    Setting the 'secure' flag on a cookie to False can cause it to be sent in cleartext. +Setting the 'httponly' flag on a cookie to False may allow attackers access it via JavaScript. +Setting the 'samesite' flag on a cookie to 'None' will make the cookie to be sent in third-party +contexts which may be attacker-controlled.

    Always set secure to True or add "; Secure;" to the cookie's raw value.

    +

    Always set httponly to True or add "; HttpOnly;" to the cookie's raw value.

    +

    Always set samesite to Lax or Strict, or add "; SameSite=Lax;", or +"; Samesite=Strict;" to the cookie's raw header value.

    diff --git a/python/ql/src/experimental/semmle/python/CookieHeader.qll b/python/ql/src/experimental/semmle/python/CookieHeader.qll index c7779aadd80..ab6bde4bb82 100644 --- a/python/ql/src/experimental/semmle/python/CookieHeader.qll +++ b/python/ql/src/experimental/semmle/python/CookieHeader.qll @@ -7,6 +7,25 @@ import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TaintTracking import experimental.semmle.python.Concepts +/** + * Gets a header setting a cookie. + * + * Given the following example: + * + * ```py + * @app.route("/") + * def flask_make_response(): + * resp = make_response("") + * resp.headers['Set-Cookie'] = "name=value; Secure;" + * return resp + * ``` + * + * * `this` would be `resp.headers['Set-Cookie'] = "name=value; Secure;"`. + * * `isSecure()` predicate would succeed. + * * `isHttpOnly()` predicate would fail. + * * `isSameSite()` predicate would fail. + * * `getName()` and `getValue()` results would be `"name=value; Secure;"`. + */ class CookieHeader extends HeaderDeclaration, Cookie::Range { CookieHeader() { this instanceof HeaderDeclaration and diff --git a/python/ql/src/experimental/semmle/python/frameworks/Django.qll b/python/ql/src/experimental/semmle/python/frameworks/Django.qll index ba99ddaa800..7fb7b65989e 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Django.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Django.qll @@ -87,6 +87,25 @@ private module PrivateDjango { override DataFlow::Node getValueArg() { result = headerInput } } + /** + * Gets a call to `set_cookie()`. + * + * Given the following example: + * + * ```py + * def django_response(request): + * resp = django.http.HttpResponse() + * resp.set_cookie("name", "value", secure=True, httponly=True, samesite='Lax') + * return resp + * ``` + * + * * `this` would be `resp.set_cookie("name", "value", secure=False, httponly=False, samesite='None')`. + * * `getName()`'s result would be `"name"`. + * * `getValue()`'s result would be `"value"`. + * * `isSecure()` predicate would succeed. + * * `isHttpOnly()` predicate would succeed. + * * `isSameSite()` predicate would succeed. + */ class DjangoSetCookieCall extends DataFlow::CallCfgNode, Cookie::Range { DjangoSetCookieCall() { this = baseClassRef().getMember("set_cookie").getACall() } diff --git a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll index b93e6713846..c07092ee761 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll @@ -82,6 +82,26 @@ module ExperimentalFlask { override DataFlow::Node getValueArg() { result.asExpr() = item.getValue() } } + /** + * Gets a call to `set_cookie()`. + * + * Given the following example: + * + * ```py + * @app.route("/") + * def false(): + * resp = make_response() + * resp.set_cookie("name", value="value", secure=True, httponly=True, samesite='Lax') + * return resp + * ``` + * + * * `this` would be `resp.set_cookie("name", value="value", secure=False, httponly=False, samesite='None')`. + * * `getName()`'s result would be `"name"`. + * * `getValue()`'s result would be `"value"`. + * * `isSecure()` predicate would succeed. + * * `isHttpOnly()` predicate would succeed. + * * `isSameSite()` predicate would succeed. + */ class FlaskSetCookieCall extends DataFlow::CallCfgNode, Cookie::Range { FlaskSetCookieCall() { this = From e7d649f36dd74321f4588cfd9c3d0e69e5b00ce1 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Tue, 16 Nov 2021 13:54:25 +0100 Subject: [PATCH 020/171] Make `Cookie` concept extend `HTTP::Server::CookieWrite` --- .../experimental/semmle/python/Concepts.qll | 35 ++++--------------- .../semmle/python/CookieHeader.qll | 8 +++-- .../semmle/python/frameworks/Django.qll | 6 ++-- .../semmle/python/frameworks/Flask.qll | 6 ++-- .../security/injection/CookieInjection.qll | 4 +-- .../Security/CWE-614/CookieInjection.expected | 3 ++ 6 files changed, 24 insertions(+), 38 deletions(-) diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll index 64aa755d9cf..91b1a5f777d 100644 --- a/python/ql/src/experimental/semmle/python/Concepts.qll +++ b/python/ql/src/experimental/semmle/python/Concepts.qll @@ -13,6 +13,7 @@ private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.TaintTracking private import experimental.semmle.python.Frameworks +private import semmle.python.Concepts /** Provides classes for modeling log related APIs. */ module LogOutput { @@ -303,35 +304,21 @@ class HeaderDeclaration extends DataFlow::Node { * Extend this class to refine existing API models. If you want to model new APIs, * extend `Cookie::Range` instead. */ -class Cookie extends DataFlow::Node { - Cookie::Range range; - - Cookie() { this = range } - +class Cookie extends HTTP::Server::CookieWrite instanceof Cookie::Range { /** * Holds if this cookie is secure. */ - predicate isSecure() { range.isSecure() } + predicate isSecure() { super.isSecure() } /** * Holds if this cookie is HttpOnly. */ - predicate isHttpOnly() { range.isHttpOnly() } + predicate isHttpOnly() { super.isHttpOnly() } /** * Holds if the cookie is SameSite */ - predicate isSameSite() { range.isSameSite() } - - /** - * Gets the argument containing the header name. - */ - DataFlow::Node getName() { result = range.getName() } - - /** - * Gets the argument containing the header value. - */ - DataFlow::Node getValue() { result = range.getValue() } + predicate isSameSite() { super.isSameSite() } } /** Provides a class for modeling new cookie writes on HTTP responses. */ @@ -342,7 +329,7 @@ module Cookie { * Extend this class to model new APIs. If you want to refine existing API models, * extend `Cookie` instead. */ - abstract class Range extends DataFlow::Node { + abstract class Range extends HTTP::Server::CookieWrite::Range { /** * Holds if this cookie is secure. */ @@ -357,15 +344,5 @@ module Cookie { * Holds if the cookie is SameSite. */ abstract predicate isSameSite(); - - /** - * Gets the argument containing the header name. - */ - abstract DataFlow::Node getName(); - - /** - * Gets the argument containing the header value. - */ - abstract DataFlow::Node getValue(); } } diff --git a/python/ql/src/experimental/semmle/python/CookieHeader.qll b/python/ql/src/experimental/semmle/python/CookieHeader.qll index ab6bde4bb82..2fda527c69f 100644 --- a/python/ql/src/experimental/semmle/python/CookieHeader.qll +++ b/python/ql/src/experimental/semmle/python/CookieHeader.qll @@ -26,7 +26,7 @@ import experimental.semmle.python.Concepts * * `isSameSite()` predicate would fail. * * `getName()` and `getValue()` results would be `"name=value; Secure;"`. */ -class CookieHeader extends HeaderDeclaration, Cookie::Range { +class CookieHeader extends Cookie::Range instanceof HeaderDeclaration { CookieHeader() { this instanceof HeaderDeclaration and this.(HeaderDeclaration).getNameArg().asExpr().(Str_).getS() = "Set-Cookie" @@ -49,7 +49,9 @@ class CookieHeader extends HeaderDeclaration, Cookie::Range { .regexpMatch(".*; *SameSite=(Strict|Lax);.*") } - override DataFlow::Node getName() { result = this.(HeaderDeclaration).getValueArg() } + override DataFlow::Node getNameArg() { result = this.(HeaderDeclaration).getValueArg() } - override DataFlow::Node getValue() { result = this.(HeaderDeclaration).getValueArg() } + override DataFlow::Node getValueArg() { result = this.(HeaderDeclaration).getValueArg() } + + override DataFlow::Node getHeaderArg() { none() } } diff --git a/python/ql/src/experimental/semmle/python/frameworks/Django.qll b/python/ql/src/experimental/semmle/python/frameworks/Django.qll index 7fb7b65989e..11b4665d6c8 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Django.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Django.qll @@ -109,9 +109,9 @@ private module PrivateDjango { class DjangoSetCookieCall extends DataFlow::CallCfgNode, Cookie::Range { DjangoSetCookieCall() { this = baseClassRef().getMember("set_cookie").getACall() } - override DataFlow::Node getName() { result = this.getArg(0) } + override DataFlow::Node getNameArg() { result = this.getArg(0) } - override DataFlow::Node getValue() { result = this.getArgByName("value") } + override DataFlow::Node getValueArg() { result = this.getArgByName("value") } override predicate isSecure() { DataFlow::exprNode(any(True t)) @@ -128,6 +128,8 @@ private module PrivateDjango { override predicate isSameSite() { this.getArgByName("samesite").asExpr().(Str_).getS() in ["Strict", "Lax"] } + + override DataFlow::Node getHeaderArg() { none() } } } } diff --git a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll index c07092ee761..92a019599c0 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll @@ -111,9 +111,9 @@ module ExperimentalFlask { .getACall() } - override DataFlow::Node getName() { result = this.getArg(0) } + override DataFlow::Node getNameArg() { result = this.getArg(0) } - override DataFlow::Node getValue() { result = this.getArgByName("value") } + override DataFlow::Node getValueArg() { result = this.getArgByName("value") } override predicate isSecure() { DataFlow::exprNode(any(True t)) @@ -130,5 +130,7 @@ module ExperimentalFlask { override predicate isSameSite() { this.getArgByName("samesite").asExpr().(Str_).getS() in ["Strict", "Lax"] } + + override DataFlow::Node getHeaderArg() { none() } } } diff --git a/python/ql/src/experimental/semmle/python/security/injection/CookieInjection.qll b/python/ql/src/experimental/semmle/python/security/injection/CookieInjection.qll index 41f7c2af7d3..87f3b1fd76b 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/CookieInjection.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/CookieInjection.qll @@ -9,7 +9,7 @@ class CookieSink extends DataFlow::Node { CookieSink() { exists(Cookie cookie | - this in [cookie.getName(), cookie.getValue()] and + this in [cookie.getNameArg(), cookie.getValueArg()] and ( not cookie.isSecure() and flag = "secure" @@ -35,6 +35,6 @@ class CookieInjectionFlowConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } override predicate isSink(DataFlow::Node sink) { - exists(Cookie c | sink in [c.getName(), c.getValue()]) + exists(Cookie c | sink in [c.getNameArg(), c.getValueArg()]) } } diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected index fc368c95323..879b1088002 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected @@ -1,6 +1,9 @@ | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | and its httponly flag is not properly set | | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | and its samesite flag is not properly set | | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | and its secure flag is not properly set | +| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input | and its httponly flag is not properly set | +| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input | and its samesite flag is not properly set | +| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input | and its secure flag is not properly set | | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | and its httponly flag is not properly set | | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | and its samesite flag is not properly set | | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | and its secure flag is not properly set | From 6ecb6d1a1b599104590c11d7e6febbbaf4e06e8b Mon Sep 17 00:00:00 2001 From: jorgectf Date: Tue, 16 Nov 2021 14:59:41 +0100 Subject: [PATCH 021/171] Adapt Django and Flask to their main modelings --- .../semmle/python/frameworks/Django.qll | 73 ++++++++++++++++--- .../semmle/python/frameworks/Flask.qll | 23 +++--- 2 files changed, 71 insertions(+), 25 deletions(-) diff --git a/python/ql/src/experimental/semmle/python/frameworks/Django.qll b/python/ql/src/experimental/semmle/python/frameworks/Django.qll index 11b4665d6c8..1c2d13f76cf 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Django.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Django.qll @@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.DataFlow private import experimental.semmle.python.Concepts private import semmle.python.ApiGraphs import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.Concepts private module PrivateDjango { private module django { @@ -32,22 +33,64 @@ private module PrivateDjango { module response { module HttpResponse { API::Node baseClassRef() { - result = response().getMember("HttpResponse").getReturn() + result = response().getMember("HttpResponse") or // Handle `django.http.HttpResponse` alias - result = http().getMember("HttpResponse").getReturn() + result = http().getMember("HttpResponse") } + /** Gets a reference to the `django.http.response.HttpResponse` class. */ + API::Node classRef() { result = baseClassRef().getASubclass*() } + + /** + * A source of instances of `django.http.response.HttpResponse`, extend this class to model new instances. + * + * This can include instantiations of the class, return values from function + * calls, or a special parameter that will be set when functions are called by an external + * library. + * + * Use the predicate `HttpResponse::instance()` to get references to instances of `django.http.response.HttpResponse`. + */ + abstract class InstanceSource extends HTTP::Server::HttpResponse::Range, DataFlow::Node { + } + + /** A direct instantiation of `django.http.response.HttpResponse`. */ + private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode { + ClassInstantiation() { this = classRef().getACall() } + + override DataFlow::Node getBody() { + result in [this.getArg(0), this.getArgByName("content")] + } + + // How to support the `headers` argument here? + override DataFlow::Node getMimetypeOrContentTypeArg() { + result in [this.getArg(1), this.getArgByName("content_type")] + } + + override string getMimetypeDefault() { result = "text/html" } + } + + /** Gets a reference to an instance of `django.http.response.HttpResponse`. */ + private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { + t.start() and + result instanceof InstanceSource + or + exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) + } + + /** Gets a reference to an instance of `django.http.response.HttpResponse`. */ + DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } + /** Gets a reference to a header instance. */ private DataFlow::LocalSourceNode headerInstance(DataFlow::TypeTracker t) { t.start() and ( exists(SubscriptNode subscript | - subscript.getObject() = baseClassRef().getAUse().asCfgNode() and + subscript.getObject() = baseClassRef().getReturn().getAUse().asCfgNode() and result.asCfgNode() = subscript ) or - result.(DataFlow::AttrRead).getObject() = baseClassRef().getAUse() + result.(DataFlow::AttrRead).getObject() = baseClassRef().getReturn().getAUse() ) or exists(DataFlow::TypeTracker t2 | result = headerInstance(t2).track(t2, t)) @@ -106,27 +149,35 @@ private module PrivateDjango { * * `isHttpOnly()` predicate would succeed. * * `isSameSite()` predicate would succeed. */ - class DjangoSetCookieCall extends DataFlow::CallCfgNode, Cookie::Range { - DjangoSetCookieCall() { this = baseClassRef().getMember("set_cookie").getACall() } + class DjangoResponseSetCookieCall extends DataFlow::MethodCallNode, Cookie::Range { + DjangoResponseSetCookieCall() { + this.calls(django::http::response::HttpResponse::instance(), "set_cookie") + } - override DataFlow::Node getNameArg() { result = this.getArg(0) } + override DataFlow::Node getNameArg() { + result in [this.getArg(0), this.getArgByName("key")] + } - override DataFlow::Node getValueArg() { result = this.getArgByName("value") } + override DataFlow::Node getValueArg() { + result in [this.getArg(1), this.getArgByName("value")] + } override predicate isSecure() { DataFlow::exprNode(any(True t)) .(DataFlow::LocalSourceNode) - .flowsTo(this.getArgByName("secure")) + .flowsTo(this.(DataFlow::CallCfgNode).getArgByName("secure")) } override predicate isHttpOnly() { DataFlow::exprNode(any(True t)) .(DataFlow::LocalSourceNode) - .flowsTo(this.getArgByName("httponly")) + .flowsTo(this.(DataFlow::CallCfgNode).getArgByName("httponly")) } override predicate isSameSite() { - this.getArgByName("samesite").asExpr().(Str_).getS() in ["Strict", "Lax"] + this.(DataFlow::CallCfgNode).getArgByName("samesite").asExpr().(Str_).getS() in [ + "Strict", "Lax" + ] } override DataFlow::Node getHeaderArg() { none() } diff --git a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll index 92a019599c0..c07abc0e177 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll @@ -8,6 +8,7 @@ private import semmle.python.frameworks.Flask private import semmle.python.dataflow.new.DataFlow private import experimental.semmle.python.Concepts private import semmle.python.ApiGraphs +private import semmle.python.frameworks.Flask module ExperimentalFlask { /** @@ -102,33 +103,27 @@ module ExperimentalFlask { * * `isHttpOnly()` predicate would succeed. * * `isSameSite()` predicate would succeed. */ - class FlaskSetCookieCall extends DataFlow::CallCfgNode, Cookie::Range { - FlaskSetCookieCall() { - this = - [Flask::Response::classRef(), flaskMakeResponse()] - .getReturn() - .getMember("set_cookie") - .getACall() - } + class FlaskSetCookieCall extends Cookie::Range instanceof Flask::FlaskResponseSetCookieCall { + override DataFlow::Node getNameArg() { result = this.getNameArg() } - override DataFlow::Node getNameArg() { result = this.getArg(0) } - - override DataFlow::Node getValueArg() { result = this.getArgByName("value") } + override DataFlow::Node getValueArg() { result = this.getValueArg() } override predicate isSecure() { DataFlow::exprNode(any(True t)) .(DataFlow::LocalSourceNode) - .flowsTo(this.getArgByName("secure")) + .flowsTo(this.(DataFlow::CallCfgNode).getArgByName("secure")) } override predicate isHttpOnly() { DataFlow::exprNode(any(True t)) .(DataFlow::LocalSourceNode) - .flowsTo(this.getArgByName("httponly")) + .flowsTo(this.(DataFlow::CallCfgNode).getArgByName("httponly")) } override predicate isSameSite() { - this.getArgByName("samesite").asExpr().(Str_).getS() in ["Strict", "Lax"] + this.(DataFlow::CallCfgNode).getArgByName("samesite").asExpr().(Str_).getS() in [ + "Strict", "Lax" + ] } override DataFlow::Node getHeaderArg() { none() } From a4204cc04f3dd7886017e1db6d7787354ca673d4 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Tue, 16 Nov 2021 19:00:04 +0100 Subject: [PATCH 022/171] Avoid using `Str_` internal class --- .../src/experimental/semmle/python/frameworks/Django.qll | 9 ++++++--- .../src/experimental/semmle/python/frameworks/Flask.qll | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/python/ql/src/experimental/semmle/python/frameworks/Django.qll b/python/ql/src/experimental/semmle/python/frameworks/Django.qll index 1c2d13f76cf..2fef35d276c 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Django.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Django.qll @@ -175,9 +175,12 @@ private module PrivateDjango { } override predicate isSameSite() { - this.(DataFlow::CallCfgNode).getArgByName("samesite").asExpr().(Str_).getS() in [ - "Strict", "Lax" - ] + exists(StrConst str | + str.getText() in ["Strict", "Lax"] and + DataFlow::exprNode(str) + .(DataFlow::LocalSourceNode) + .flowsTo(this.(DataFlow::CallCfgNode).getArgByName("samesite")) + ) } override DataFlow::Node getHeaderArg() { none() } diff --git a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll index c07abc0e177..b9283dafd92 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll @@ -121,9 +121,12 @@ module ExperimentalFlask { } override predicate isSameSite() { - this.(DataFlow::CallCfgNode).getArgByName("samesite").asExpr().(Str_).getS() in [ - "Strict", "Lax" - ] + exists(StrConst str | + str.getText() in ["Strict", "Lax"] and + DataFlow::exprNode(str) + .(DataFlow::LocalSourceNode) + .flowsTo(this.(DataFlow::CallCfgNode).getArgByName("samesite")) + ) } override DataFlow::Node getHeaderArg() { none() } From 840cded9b022c300db528f3e3b7bf73789fdafad Mon Sep 17 00:00:00 2001 From: jorgectf Date: Tue, 16 Nov 2021 19:18:00 +0100 Subject: [PATCH 023/171] Avoid using `Str_` in `CookieHeader` --- .../semmle/python/CookieHeader.qll | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/python/ql/src/experimental/semmle/python/CookieHeader.qll b/python/ql/src/experimental/semmle/python/CookieHeader.qll index 2fda527c69f..1d28548e5a4 100644 --- a/python/ql/src/experimental/semmle/python/CookieHeader.qll +++ b/python/ql/src/experimental/semmle/python/CookieHeader.qll @@ -29,24 +29,39 @@ import experimental.semmle.python.Concepts class CookieHeader extends Cookie::Range instanceof HeaderDeclaration { CookieHeader() { this instanceof HeaderDeclaration and - this.(HeaderDeclaration).getNameArg().asExpr().(Str_).getS() = "Set-Cookie" + exists(StrConst str | + str.getText() = "Set-Cookie" and + DataFlow::exprNode(str) + .(DataFlow::LocalSourceNode) + .flowsTo(this.(HeaderDeclaration).getNameArg()) + ) } override predicate isSecure() { - this.(HeaderDeclaration).getValueArg().asExpr().(Str_).getS().regexpMatch(".*; *Secure;.*") + exists(StrConst str | + str.getText().regexpMatch(".*; *Secure;.*") and + DataFlow::exprNode(str) + .(DataFlow::LocalSourceNode) + .flowsTo(this.(HeaderDeclaration).getValueArg()) + ) } override predicate isHttpOnly() { - this.(HeaderDeclaration).getValueArg().asExpr().(Str_).getS().regexpMatch(".*; *HttpOnly;.*") + exists(StrConst str | + str.getText().regexpMatch(".*; *HttpOnly;.*") and + DataFlow::exprNode(str) + .(DataFlow::LocalSourceNode) + .flowsTo(this.(HeaderDeclaration).getValueArg()) + ) } override predicate isSameSite() { - this.(HeaderDeclaration) - .getValueArg() - .asExpr() - .(Str_) - .getS() - .regexpMatch(".*; *SameSite=(Strict|Lax);.*") + exists(StrConst str | + str.getText().regexpMatch(".*; *SameSite=(Strict|Lax);.*") and + DataFlow::exprNode(str) + .(DataFlow::LocalSourceNode) + .flowsTo(this.(HeaderDeclaration).getValueArg()) + ) } override DataFlow::Node getNameArg() { result = this.(HeaderDeclaration).getValueArg() } From 93750fe17fbc1133642d6a7af63826b314d19d15 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 4 Mar 2022 12:47:23 +0100 Subject: [PATCH 024/171] python: minimal CSRF implementation - currectly only looks for custom django middleware --- python/ql/lib/semmle/python/Concepts.qll | 31 ++++++++++ .../lib/semmle/python/frameworks/Django.qll | 31 ++++++++++ .../CWE-352/CSRFProtectionDisabled.qhelp | 60 +++++++++++++++++++ .../CWE-352/CSRFProtectionDisabled.ql | 19 ++++++ .../src/Security/CWE-352/examples/setting.py | 9 +++ 5 files changed, 150 insertions(+) create mode 100644 python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp create mode 100644 python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql create mode 100644 python/ql/src/Security/CWE-352/examples/setting.py diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 6c67b0e5d91..8e4f810d4a0 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -105,6 +105,37 @@ module FileSystemWriteAccess { } } +/** + * A data-flow node that may set or unset Cross-site request forgery protection. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `CSRFProtectionSetting::Range` instead. + */ +class CSRFProtectionSetting extends DataFlow::Node instanceof CSRFProtectionSetting::Range { + /** + * Gets the boolean value corresponding to if CSRF protection is enabled + * (`true`) or disabled (`false`) by this node. + */ + boolean getVerificationSetting() { result = super.getVerificationSetting() } +} + +/** Provides a class for modeling new CSRF protection setting APIs. */ +module CSRFProtectionSetting { + /** + * A data-flow node that may set or unset Cross-site request forgery protection. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `CSRFProtectionSetting` instead. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets the boolean value corresponding to if CSRF protection is enabled + * (`true`) or disabled (`false`) by this node. + */ + abstract boolean getVerificationSetting(); + } +} + /** Provides classes for modeling path-related APIs. */ module Path { /** diff --git a/python/ql/lib/semmle/python/frameworks/Django.qll b/python/ql/lib/semmle/python/frameworks/Django.qll index 8f34043f093..f5989badfe4 100644 --- a/python/ql/lib/semmle/python/frameworks/Django.qll +++ b/python/ql/lib/semmle/python/frameworks/Django.qll @@ -2313,4 +2313,35 @@ module PrivateDjango { .getAnImmediateUse() } } + + // --------------------------------------------------------------------------- + // Settings + // --------------------------------------------------------------------------- + /** + * A custom middleware stack + */ + private class DjangoSettingsMiddlewareStack extends CSRFProtectionSetting::Range { + List list; + + DjangoSettingsMiddlewareStack() { + this.asExpr() = list and + // we look for an assignment to the `MIDDLEWARE` setting + exists(DataFlow::Node mw, string djangomw | + mw.asVar().getName() = "MIDDLEWARE" and + DataFlow::localFlow(this, mw) + | + // check that the list contains at least one reference to `django` + list.getAnElt().(StrConst).getText() = djangomw and + // TODO: Consider requiring `django.middleware.security.SecurityMiddleware` + // or something indicating that a security middleware is enabled. + djangomw.matches("django.%") + ) + } + + override boolean getVerificationSetting() { + if list.getAnElt().(StrConst).getText() = "django.middleware.csrf.CsrfViewMiddleware" + then result = true + else result = false + } + } } diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp new file mode 100644 index 00000000000..98a5dae20ba --- /dev/null +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp @@ -0,0 +1,60 @@ + + + + +

    + Cross-site request forgery (CSRF) is a type of vulnerability in which an + attacker is able to force a user carry out an action that the user did + not intend. +

    + +

    + The attacker tricks an authenticated user into submitting a request to the + web application. Typically this request will result in a state change on + the server, such as changing the user's password. The request can be + initiated when the user visits a site controlled by the attacker. If the + web application relies only on cookies for authentication, or on other + credentials that are automatically included in the request, then this + request will appear as legitimate to the server. +

    + +

    + A common countermeasure for CSRF is to generate a unique token to be + included in the HTML sent from the server to a user. This token can be + used as a hidden field to be sent back with requests to the server, where + the server can then check that the token is valid and associated with the + relevant user session. +

    +
    + + +

    + In many web frameworks, CSRF protection is enabled by default. In these + cases, using the default configuration is sufficient to guard against most + CSRF attacks. +

    +
    + + +

    + The following example shows a case where CSRF protection is disabled by + overriding the default middleware stack and not including the one protecting against CSRF. +

    + + + +

    + The protecting middleware was probably commented out during a testing phase, when server-side token generation was not set up. + Simply commenting it back in (or remove the custom middleware stack) will enable CSRF protection. +

    + +
    + + +
  • Wikipedia: Cross-site request forgery
  • +
  • OWASP: Cross-site request forgery
  • +
    + +
    diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql new file mode 100644 index 00000000000..00f2cad5050 --- /dev/null +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql @@ -0,0 +1,19 @@ +/** + * @name CSRF protection weakened or disabled + * @description Disabling or weakening CSRF protection may make the application + * vulnerable to a Cross-Site Request Forgery (CSRF) attack. + * @kind problem + * @problem.severity warning + * @security-severity 8.8 + * @precision high + * @id py/csrf-protection-disabled + * @tags security + * external/cwe/cwe-352 + */ + +import python +import semmle.python.Concepts + +from CSRFProtectionSetting s +where s.getVerificationSetting() = false +select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened." diff --git a/python/ql/src/Security/CWE-352/examples/setting.py b/python/ql/src/Security/CWE-352/examples/setting.py new file mode 100644 index 00000000000..d1f1f983cef --- /dev/null +++ b/python/ql/src/Security/CWE-352/examples/setting.py @@ -0,0 +1,9 @@ +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + # 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] From 895ce755c1891da7285adcec45e095eca1667975 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 7 Mar 2022 13:03:04 +0100 Subject: [PATCH 025/171] python: correct file name --- .../ql/src/Security/CWE-352/examples/{setting.py => settings.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename python/ql/src/Security/CWE-352/examples/{setting.py => settings.py} (100%) diff --git a/python/ql/src/Security/CWE-352/examples/setting.py b/python/ql/src/Security/CWE-352/examples/settings.py similarity index 100% rename from python/ql/src/Security/CWE-352/examples/setting.py rename to python/ql/src/Security/CWE-352/examples/settings.py From f5b53083ae77a6a9ed459e9189877cb7326f2ed1 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 22 Mar 2022 08:44:19 +0100 Subject: [PATCH 026/171] python: require authentication middleware for CSRF to be relevant --- python/ql/lib/semmle/python/frameworks/Django.qll | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Django.qll b/python/ql/lib/semmle/python/frameworks/Django.qll index f5989badfe4..ee273a9f2a6 100644 --- a/python/ql/lib/semmle/python/frameworks/Django.qll +++ b/python/ql/lib/semmle/python/frameworks/Django.qll @@ -2326,15 +2326,16 @@ module PrivateDjango { DjangoSettingsMiddlewareStack() { this.asExpr() = list and // we look for an assignment to the `MIDDLEWARE` setting - exists(DataFlow::Node mw, string djangomw | + exists(DataFlow::Node mw | mw.asVar().getName() = "MIDDLEWARE" and DataFlow::localFlow(this, mw) | - // check that the list contains at least one reference to `django` - list.getAnElt().(StrConst).getText() = djangomw and - // TODO: Consider requiring `django.middleware.security.SecurityMiddleware` - // or something indicating that a security middleware is enabled. - djangomw.matches("django.%") + // it only counts as setting the CSRF protection, if the app uses authentication, + // so check that the list contains the django authentication middleware. + // + // This also strongly implies that we are actually looking at the `MIDDLEWARE` setting. + list.getAnElt().(StrConst).getText() = + "django.contrib.auth.middleware.AuthenticationMiddleware" ) } From 0f2c21c8bd6f953a41ed13721e93de8245b2fd1a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 22 Mar 2022 13:42:52 +0100 Subject: [PATCH 027/171] python: require local protection to be absent for CSRF to be likely --- python/ql/lib/semmle/python/Concepts.qll | 39 ++++++++++++++++++- .../lib/semmle/python/frameworks/Django.qll | 17 ++++++++ .../CWE-352/CSRFProtectionDisabled.ql | 4 +- .../frameworks/django-v2-v3/response_test.py | 2 + 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 8e4f810d4a0..04d4d63aca3 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -106,7 +106,8 @@ module FileSystemWriteAccess { } /** - * A data-flow node that may set or unset Cross-site request forgery protection. + * A data-flow node that may set or unset Cross-site request forgery protection + * in a global manner. * * Extend this class to refine existing API models. If you want to model new APIs, * extend `CSRFProtectionSetting::Range` instead. @@ -122,7 +123,8 @@ class CSRFProtectionSetting extends DataFlow::Node instanceof CSRFProtectionSett /** Provides a class for modeling new CSRF protection setting APIs. */ module CSRFProtectionSetting { /** - * A data-flow node that may set or unset Cross-site request forgery protection. + * A data-flow node that may set or unset Cross-site request forgery protection + * in a global manner. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `CSRFProtectionSetting` instead. @@ -136,6 +138,39 @@ module CSRFProtectionSetting { } } +/** + * A data-flow node that provides Cross-site request forgery protection + * for a specific part of an application. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `CSRFProtection::Range` instead. + */ +class CSRFProtection extends DataFlow::Node instanceof CSRFProtection::Range { + /** + * Gets a `Function` representing the protected interaction + * (probably a request handler). + */ + Function getProtected() { result = super.getProtected() } +} + +/** Provides a class for modeling new CSRF protection setting APIs. */ +module CSRFProtection { + /** + * A data-flow node that provides Cross-site request forgery protection + * for a specific part of an application. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `CSRFProtection` instead. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets a `Function` representing the protected interaction + * (probably a request handler). + */ + abstract Function getProtected(); + } +} + /** Provides classes for modeling path-related APIs. */ module Path { /** diff --git a/python/ql/lib/semmle/python/frameworks/Django.qll b/python/ql/lib/semmle/python/frameworks/Django.qll index ee273a9f2a6..baa81c682ea 100644 --- a/python/ql/lib/semmle/python/frameworks/Django.qll +++ b/python/ql/lib/semmle/python/frameworks/Django.qll @@ -2346,3 +2346,20 @@ module PrivateDjango { } } } + +private class DjangoCSRFDecorator extends CSRFProtection::Range { + Function function; + + DjangoCSRFDecorator() { + this = + API::moduleImport("django") + .getMember("views") + .getMember("decorators") + .getMember("csrf") + .getMember("csrf_protect") + .getAUse() and + this.asExpr() = function.getADecorator() + } + + override Function getProtected() { result = function } +} diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql index 00f2cad5050..489ed1ea53c 100644 --- a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql @@ -15,5 +15,7 @@ import python import semmle.python.Concepts from CSRFProtectionSetting s -where s.getVerificationSetting() = false +where + s.getVerificationSetting() = false and + not exists(CSRFProtection p) select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened." diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py b/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py index 74f306e8357..4007b2d8063 100644 --- a/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py @@ -1,5 +1,6 @@ from django.http.response import HttpResponse, HttpResponseRedirect, HttpResponsePermanentRedirect, JsonResponse, HttpResponseNotFound from django.views.generic import RedirectView +from django.views.decorators.csrf import csrf_protect import django.shortcuts import json @@ -117,6 +118,7 @@ class CustomJsonResponse(JsonResponse): def __init__(self, banner, content, *args, **kwargs): super().__init__(content, *args, content_type="text/html", **kwargs) +@csrf_protect def safe__custom_json_response(request): return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json MISSING: responseBody=Dict SPURIOUS: responseBody="ACME Responses" From 53de8287f532d14beae84b1398c18a4b033b03b6 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 22 Mar 2022 14:57:05 +0100 Subject: [PATCH 028/171] python: rule out test code for CSRF --- python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql index 489ed1ea53c..5caa19d3d88 100644 --- a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql @@ -17,5 +17,7 @@ import semmle.python.Concepts from CSRFProtectionSetting s where s.getVerificationSetting() = false and - not exists(CSRFProtection p) + not exists(CSRFProtection p) and + // rule out test code as this is a common place to turn off CSRF protection + not s.getLocation().getFile().getAbsolutePath().matches("%test%") select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened." From 441e206cfaa776cdafa775dfdee567052b5dea94 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 23 Mar 2022 11:29:27 +0100 Subject: [PATCH 029/171] python: CSRF -> Csrf --- python/ql/lib/semmle/python/Concepts.qll | 16 +++++----- .../lib/semmle/python/frameworks/Django.qll | 30 +++++++++---------- .../CWE-352/CSRFProtectionDisabled.ql | 4 +-- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 04d4d63aca3..1f4aca0b21a 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -110,9 +110,9 @@ module FileSystemWriteAccess { * in a global manner. * * Extend this class to refine existing API models. If you want to model new APIs, - * extend `CSRFProtectionSetting::Range` instead. + * extend `CsrfProtectionSetting::Range` instead. */ -class CSRFProtectionSetting extends DataFlow::Node instanceof CSRFProtectionSetting::Range { +class CsrfProtectionSetting extends DataFlow::Node instanceof CsrfProtectionSetting::Range { /** * Gets the boolean value corresponding to if CSRF protection is enabled * (`true`) or disabled (`false`) by this node. @@ -121,13 +121,13 @@ class CSRFProtectionSetting extends DataFlow::Node instanceof CSRFProtectionSett } /** Provides a class for modeling new CSRF protection setting APIs. */ -module CSRFProtectionSetting { +module CsrfProtectionSetting { /** * A data-flow node that may set or unset Cross-site request forgery protection * in a global manner. * * Extend this class to model new APIs. If you want to refine existing API models, - * extend `CSRFProtectionSetting` instead. + * extend `CsrfProtectionSetting` instead. */ abstract class Range extends DataFlow::Node { /** @@ -143,9 +143,9 @@ module CSRFProtectionSetting { * for a specific part of an application. * * Extend this class to refine existing API models. If you want to model new APIs, - * extend `CSRFProtection::Range` instead. + * extend `CsrfLocalProtection::Range` instead. */ -class CSRFProtection extends DataFlow::Node instanceof CSRFProtection::Range { +class CsrfLocalProtection extends DataFlow::Node instanceof CsrfLocalProtection::Range { /** * Gets a `Function` representing the protected interaction * (probably a request handler). @@ -154,13 +154,13 @@ class CSRFProtection extends DataFlow::Node instanceof CSRFProtection::Range { } /** Provides a class for modeling new CSRF protection setting APIs. */ -module CSRFProtection { +module CsrfLocalProtection { /** * A data-flow node that provides Cross-site request forgery protection * for a specific part of an application. * * Extend this class to model new APIs. If you want to refine existing API models, - * extend `CSRFProtection` instead. + * extend `CsrfLocalProtection` instead. */ abstract class Range extends DataFlow::Node { /** diff --git a/python/ql/lib/semmle/python/frameworks/Django.qll b/python/ql/lib/semmle/python/frameworks/Django.qll index baa81c682ea..efa1a0eaa48 100644 --- a/python/ql/lib/semmle/python/frameworks/Django.qll +++ b/python/ql/lib/semmle/python/frameworks/Django.qll @@ -2320,7 +2320,7 @@ module PrivateDjango { /** * A custom middleware stack */ - private class DjangoSettingsMiddlewareStack extends CSRFProtectionSetting::Range { + private class DjangoSettingsMiddlewareStack extends CsrfProtectionSetting::Range { List list; DjangoSettingsMiddlewareStack() { @@ -2345,21 +2345,21 @@ module PrivateDjango { else result = false } } -} -private class DjangoCSRFDecorator extends CSRFProtection::Range { - Function function; + private class DjangoCsrfDecorator extends CsrfLocalProtection::Range { + Function function; - DjangoCSRFDecorator() { - this = - API::moduleImport("django") - .getMember("views") - .getMember("decorators") - .getMember("csrf") - .getMember("csrf_protect") - .getAUse() and - this.asExpr() = function.getADecorator() + DjangoCsrfDecorator() { + this = + API::moduleImport("django") + .getMember("views") + .getMember("decorators") + .getMember("csrf") + .getMember("csrf_protect") + .getAUse() and + this.asExpr() = function.getADecorator() + } + + override Function getProtected() { result = function } } - - override Function getProtected() { result = function } } diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql index 5caa19d3d88..91609c25adb 100644 --- a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql @@ -14,10 +14,10 @@ import python import semmle.python.Concepts -from CSRFProtectionSetting s +from CsrfProtectionSetting s where s.getVerificationSetting() = false and - not exists(CSRFProtection p) and + not exists(CsrfLocalProtection p) and // rule out test code as this is a common place to turn off CSRF protection not s.getLocation().getFile().getAbsolutePath().matches("%test%") select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened." From 6c2449564a768a96989e8c60fae4d041a39bd80b Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 23 Mar 2022 12:05:09 +0100 Subject: [PATCH 030/171] python: add concept tests --- .../test/experimental/meta/ConceptsTest.qll | 32 +++++++++++++++++++ .../frameworks/django-v2-v3/response_test.py | 2 +- .../django-v2-v3/testproj/settings.py | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 517f3a50bf7..6fd15e586f5 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -503,3 +503,35 @@ class HttpClientRequestTest extends InlineExpectationsTest { ) } } + +class CsrfProtectionSettingTest extends InlineExpectationsTest { + CsrfProtectionSettingTest() { this = "CsrfProtectionSettingTest" } + + override string getARelevantTag() { result = "CsrfProtectionSetting" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(CsrfProtectionSetting setting | + location = setting.getLocation() and + element = setting.toString() and + value = setting.getVerificationSetting().toString() and + tag = "CsrfProtectionSetting" + ) + } +} + +class CsrfLocalProtectionTest extends InlineExpectationsTest { + CsrfLocalProtectionTest() { this = "CsrfLocalProtectionTest" } + + override string getARelevantTag() { result = "CsrfLocalProtection" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(CsrfLocalProtection p | + location = p.getLocation() and + element = p.toString() and + value = p.getProtected().getName().toString() and + tag = "CsrfLocalProtection" + ) + } +} diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py b/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py index 4007b2d8063..73517f261fd 100644 --- a/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py @@ -118,7 +118,7 @@ class CustomJsonResponse(JsonResponse): def __init__(self, banner, content, *args, **kwargs): super().__init__(content, *args, content_type="text/html", **kwargs) -@csrf_protect +@csrf_protect # $CsrfLocalProtection=safe__custom_json_response def safe__custom_json_response(request): return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json MISSING: responseBody=Dict SPURIOUS: responseBody="ACME Responses" diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/settings.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/settings.py index 5343182c1c9..7a0c10a21f6 100644 --- a/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/settings.py +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/settings.py @@ -40,7 +40,7 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', ] -MIDDLEWARE = [ +MIDDLEWARE = [ # $CsrfProtectionSetting=false 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', From 93336bcb16cedf671e8a1665c3b7ffeb45dfa0b5 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 23 Mar 2022 12:27:51 +0100 Subject: [PATCH 031/171] python: allow alternative middleware (observed [on LGTM](https://lgtm.com/projects/g/mozilla/mozillians/snapshot/9d6a7ee180addf7652fce96c21bafbad14d1dda7/files/mozillians/settings.py?sort=name&dir=ASC&mode=heatmap#L96)) --- python/ql/lib/semmle/python/frameworks/Django.qll | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/frameworks/Django.qll b/python/ql/lib/semmle/python/frameworks/Django.qll index efa1a0eaa48..d623c663442 100644 --- a/python/ql/lib/semmle/python/frameworks/Django.qll +++ b/python/ql/lib/semmle/python/frameworks/Django.qll @@ -2340,7 +2340,12 @@ module PrivateDjango { } override boolean getVerificationSetting() { - if list.getAnElt().(StrConst).getText() = "django.middleware.csrf.CsrfViewMiddleware" + if + list.getAnElt().(StrConst).getText() in [ + "django.middleware.csrf.CsrfViewMiddleware", + // see https://github.com/mozilla/django-session-csrf + "session_csrf.CsrfMiddleware" + ] then result = true else result = false } From aecf4e48f8cd18526440fcdcfd400be2c733c013 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 24 Mar 2022 11:43:07 +0100 Subject: [PATCH 032/171] python: add change note --- python/ql/src/change-notes/2022-03-24-csrf-protection.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 python/ql/src/change-notes/2022-03-24-csrf-protection.md diff --git a/python/ql/src/change-notes/2022-03-24-csrf-protection.md b/python/ql/src/change-notes/2022-03-24-csrf-protection.md new file mode 100644 index 00000000000..fc733b7b030 --- /dev/null +++ b/python/ql/src/change-notes/2022-03-24-csrf-protection.md @@ -0,0 +1,4 @@ +--- + category: newQuery + --- + * The query "CSRF protection weakened or disabled" (`py/csrf-protection-disabled`) has been implemented. Its results will now appear by default. \ No newline at end of file From ce017394e6e8fd4242639412f5db14126c6dcb71 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 24 Mar 2022 12:01:46 +0100 Subject: [PATCH 033/171] python: fix change note (hepofully) --- python/ql/src/change-notes/2022-03-24-csrf-protection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/change-notes/2022-03-24-csrf-protection.md b/python/ql/src/change-notes/2022-03-24-csrf-protection.md index fc733b7b030..14a291d5f78 100644 --- a/python/ql/src/change-notes/2022-03-24-csrf-protection.md +++ b/python/ql/src/change-notes/2022-03-24-csrf-protection.md @@ -1,4 +1,4 @@ --- category: newQuery - --- - * The query "CSRF protection weakened or disabled" (`py/csrf-protection-disabled`) has been implemented. Its results will now appear by default. \ No newline at end of file +--- +* The query "CSRF protection weakened or disabled" (`py/csrf-protection-disabled`) has been implemented. Its results will now appear by default. From 85f1d92a0dfe7bb2617f440eb03ae14dba1a4e7b Mon Sep 17 00:00:00 2001 From: yoff Date: Fri, 25 Mar 2022 11:42:32 +0100 Subject: [PATCH 034/171] Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen --- python/ql/lib/semmle/python/Concepts.qll | 2 +- python/ql/lib/semmle/python/frameworks/Django.qll | 8 ++++++-- .../ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 1f4aca0b21a..31fd2a5cf0e 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -106,7 +106,7 @@ module FileSystemWriteAccess { } /** - * A data-flow node that may set or unset Cross-site request forgery protection + * A data-flow node that enables or disables Cross-site request forgery protection * in a global manner. * * Extend this class to refine existing API models. If you want to model new APIs, diff --git a/python/ql/lib/semmle/python/frameworks/Django.qll b/python/ql/lib/semmle/python/frameworks/Django.qll index d623c663442..5e7226a2f3a 100644 --- a/python/ql/lib/semmle/python/frameworks/Django.qll +++ b/python/ql/lib/semmle/python/frameworks/Django.qll @@ -2330,8 +2330,12 @@ module PrivateDjango { mw.asVar().getName() = "MIDDLEWARE" and DataFlow::localFlow(this, mw) | - // it only counts as setting the CSRF protection, if the app uses authentication, - // so check that the list contains the django authentication middleware. + // To only include results where CSRF protection matters, we only care about CSRF + // protection when the django authentication middleware is enabled. + // Since an active session cookie is exactly what would allow an attacker to perform + // a CSRF attack. + // Notice that this does not ensure that this is not a FP, since the authentication + // middleware might be unused. // // This also strongly implies that we are actually looking at the `MIDDLEWARE` setting. list.getAnElt().(StrConst).getText() = diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp index 98a5dae20ba..c9a6d4f0f16 100644 --- a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp @@ -6,7 +6,7 @@

    Cross-site request forgery (CSRF) is a type of vulnerability in which an - attacker is able to force a user carry out an action that the user did + attacker is able to force a user to carry out an action that the user did not intend.

    From 778a88f32c7575ab273d2472b6552940646b9899 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 25 Mar 2022 11:49:06 +0100 Subject: [PATCH 035/171] python: update qhelp removing custom middleware stack will _not_ enable CSRF protection --- python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp index c9a6d4f0f16..51745c11632 100644 --- a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp @@ -47,7 +47,7 @@

    The protecting middleware was probably commented out during a testing phase, when server-side token generation was not set up. - Simply commenting it back in (or remove the custom middleware stack) will enable CSRF protection. + Simply commenting it back in will enable CSRF protection.

    From 179f77b123958ba4f07e381b7b0b2e51e3f7f29f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 25 Mar 2022 11:51:24 +0100 Subject: [PATCH 036/171] python: clearer comment --- python/ql/lib/semmle/python/frameworks/Django.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/frameworks/Django.qll b/python/ql/lib/semmle/python/frameworks/Django.qll index 5e7226a2f3a..f2d0019e3fc 100644 --- a/python/ql/lib/semmle/python/frameworks/Django.qll +++ b/python/ql/lib/semmle/python/frameworks/Django.qll @@ -2337,7 +2337,8 @@ module PrivateDjango { // Notice that this does not ensure that this is not a FP, since the authentication // middleware might be unused. // - // This also strongly implies that we are actually looking at the `MIDDLEWARE` setting. + // This also strongly implies that `mw` is in fact a Django middleware setting and + // not just a variable named `MIDDLEWARE`. list.getAnElt().(StrConst).getText() = "django.contrib.auth.middleware.AuthenticationMiddleware" ) From 1e9840d7794f800037d169365ba7ec82d99e1a95 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 25 Mar 2022 12:28:33 +0100 Subject: [PATCH 037/171] python: broaden local protection concept --- python/ql/lib/semmle/python/Concepts.qll | 30 +++++++++++-------- .../lib/semmle/python/frameworks/Django.qll | 10 +++++-- .../CWE-352/CSRFProtectionDisabled.ql | 2 +- .../test/experimental/meta/ConceptsTest.qll | 14 +++++---- .../frameworks/django-v2-v3/response_test.py | 2 +- 5 files changed, 34 insertions(+), 24 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 31fd2a5cf0e..01aa16d2094 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -123,7 +123,7 @@ class CsrfProtectionSetting extends DataFlow::Node instanceof CsrfProtectionSett /** Provides a class for modeling new CSRF protection setting APIs. */ module CsrfProtectionSetting { /** - * A data-flow node that may set or unset Cross-site request forgery protection + * A data-flow node that enables or disables Cross-site request forgery protection * in a global manner. * * Extend this class to model new APIs. If you want to refine existing API models, @@ -139,35 +139,39 @@ module CsrfProtectionSetting { } /** - * A data-flow node that provides Cross-site request forgery protection + * A data-flow node that enables or disables Cross-site request forgery protection * for a specific part of an application. * * Extend this class to refine existing API models. If you want to model new APIs, - * extend `CsrfLocalProtection::Range` instead. + * extend `CsrfLocalProtectionSetting::Range` instead. */ -class CsrfLocalProtection extends DataFlow::Node instanceof CsrfLocalProtection::Range { +class CsrfLocalProtectionSetting extends DataFlow::Node instanceof CsrfLocalProtectionSetting::Range { /** - * Gets a `Function` representing the protected interaction - * (probably a request handler). + * Gets a request handler whose CSRF protection is changed. */ - Function getProtected() { result = super.getProtected() } + Function getRequestHandler() { result = super.getRequestHandler() } + + /** Holds if CSRF protection is enabled by this setting */ + predicate csrfEnabled() { super.csrfEnabled() } } /** Provides a class for modeling new CSRF protection setting APIs. */ -module CsrfLocalProtection { +module CsrfLocalProtectionSetting { /** - * A data-flow node that provides Cross-site request forgery protection + * A data-flow node that enables or disables Cross-site request forgery protection * for a specific part of an application. * * Extend this class to model new APIs. If you want to refine existing API models, - * extend `CsrfLocalProtection` instead. + * extend `CsrfLocalProtectionSetting` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets a `Function` representing the protected interaction - * (probably a request handler). + * Gets a request handler whose CSRF protection is changed. */ - abstract Function getProtected(); + abstract Function getRequestHandler(); + + /** Holds if CSRF protection is enabled by this setting */ + abstract predicate csrfEnabled(); } } diff --git a/python/ql/lib/semmle/python/frameworks/Django.qll b/python/ql/lib/semmle/python/frameworks/Django.qll index f2d0019e3fc..c2852187b48 100644 --- a/python/ql/lib/semmle/python/frameworks/Django.qll +++ b/python/ql/lib/semmle/python/frameworks/Django.qll @@ -2356,20 +2356,24 @@ module PrivateDjango { } } - private class DjangoCsrfDecorator extends CsrfLocalProtection::Range { + private class DjangoCsrfDecorator extends CsrfLocalProtectionSetting::Range { + string decoratorName; Function function; DjangoCsrfDecorator() { + decoratorName in ["csrf_protect", "csrf_exempt", "requires_csrf_token", "ensure_csrf_cookie"] and this = API::moduleImport("django") .getMember("views") .getMember("decorators") .getMember("csrf") - .getMember("csrf_protect") + .getMember(decoratorName) .getAUse() and this.asExpr() = function.getADecorator() } - override Function getProtected() { result = function } + override Function getRequestHandler() { result = function } + + override predicate csrfEnabled() { decoratorName in ["csrf_protect", "requires_csrf_token"] } } } diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql index 91609c25adb..e7202a361e5 100644 --- a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql @@ -17,7 +17,7 @@ import semmle.python.Concepts from CsrfProtectionSetting s where s.getVerificationSetting() = false and - not exists(CsrfLocalProtection p) and + not exists(CsrfLocalProtectionSetting p | p.csrfEnabled()) and // rule out test code as this is a common place to turn off CSRF protection not s.getLocation().getFile().getAbsolutePath().matches("%test%") select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened." diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 6fd15e586f5..339087d50d6 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -520,18 +520,20 @@ class CsrfProtectionSettingTest extends InlineExpectationsTest { } } -class CsrfLocalProtectionTest extends InlineExpectationsTest { - CsrfLocalProtectionTest() { this = "CsrfLocalProtectionTest" } +class CsrfLocalProtectionSettingTest extends InlineExpectationsTest { + CsrfLocalProtectionSettingTest() { this = "CsrfLocalProtectionSettingTest" } - override string getARelevantTag() { result = "CsrfLocalProtection" } + override string getARelevantTag() { result = "CsrfLocalProtection" + ["Enabled", "Disabled"] } override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and - exists(CsrfLocalProtection p | + exists(CsrfLocalProtectionSetting p | location = p.getLocation() and element = p.toString() and - value = p.getProtected().getName().toString() and - tag = "CsrfLocalProtection" + value = p.getRequestHandler().getName().toString() and + if p.csrfEnabled() + then tag = "CsrfLocalProtectionEnabled" + else tag = "CsrfLocalProtectionDisabled" ) } } diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py b/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py index 73517f261fd..dd78cd51016 100644 --- a/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py @@ -118,7 +118,7 @@ class CustomJsonResponse(JsonResponse): def __init__(self, banner, content, *args, **kwargs): super().__init__(content, *args, content_type="text/html", **kwargs) -@csrf_protect # $CsrfLocalProtection=safe__custom_json_response +@csrf_protect # $CsrfLocalProtectionEnabled=safe__custom_json_response def safe__custom_json_response(request): return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json MISSING: responseBody=Dict SPURIOUS: responseBody="ACME Responses" From f19ade3446319c4d9ac9b72f068a4a8c4cccc9c4 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sun, 27 Mar 2022 01:28:00 +0100 Subject: [PATCH 038/171] Java: Add `StmtExpr` --- .../2022-03-27-statement-expression.md | 4 ++ java/ql/lib/semmle/code/java/Collections.qll | 2 +- java/ql/lib/semmle/code/java/Expr.qll | 38 +++++++++++ java/ql/lib/semmle/code/java/Maps.qll | 2 +- .../Statements/ReturnValueIgnored.ql | 2 +- .../IgnoreExceptionalReturn.ql | 2 +- .../CWE-297/IgnoredHostnameVerification.ql | 2 +- .../library-tests/StmtExpr/StmtExpr.expected | 14 ++++ .../test/library-tests/StmtExpr/StmtExpr.java | 68 +++++++++++++++++++ .../test/library-tests/StmtExpr/StmtExpr.ql | 4 ++ java/ql/test/library-tests/StmtExpr/options | 1 + 11 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 java/ql/lib/change-notes/2022-03-27-statement-expression.md create mode 100644 java/ql/test/library-tests/StmtExpr/StmtExpr.expected create mode 100644 java/ql/test/library-tests/StmtExpr/StmtExpr.java create mode 100644 java/ql/test/library-tests/StmtExpr/StmtExpr.ql create mode 100644 java/ql/test/library-tests/StmtExpr/options diff --git a/java/ql/lib/change-notes/2022-03-27-statement-expression.md b/java/ql/lib/change-notes/2022-03-27-statement-expression.md new file mode 100644 index 00000000000..bb261f66878 --- /dev/null +++ b/java/ql/lib/change-notes/2022-03-27-statement-expression.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* The QL class `StmtExpr` has been added to model statement expressions, that is, expressions whose result is discarded. diff --git a/java/ql/lib/semmle/code/java/Collections.qll b/java/ql/lib/semmle/code/java/Collections.qll index d557d6281de..e6da65faa04 100644 --- a/java/ql/lib/semmle/code/java/Collections.qll +++ b/java/ql/lib/semmle/code/java/Collections.qll @@ -84,7 +84,7 @@ class CollectionMutation extends MethodAccess { CollectionMutation() { this.getMethod() instanceof CollectionMutator } /** Holds if the result of this call is not immediately discarded. */ - predicate resultIsChecked() { not this.getParent() instanceof ExprStmt } + predicate resultIsChecked() { not this instanceof StmtExpr } } /** A method that queries the contents of a collection without mutating it. */ diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index 8f77b1800a2..4659d0e78fc 100755 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -2133,3 +2133,41 @@ class Argument extends Expr { ) } } + +/** + * A statement expression, as specified by JLS 17 section 14.8. + * The result of a statement expression, if any, is discarded. + * + * Not to be confused with `ExprStmt`; while the child of an `ExprStmt` is always + * a `StmtExpr`, the opposite is not true. A `StmtExpr` occurs for example also + * as 'init' of a `for` statement. + */ +class StmtExpr extends Expr { + StmtExpr() { + this = any(ExprStmt s).getExpr() + or + this = any(ForStmt s).getAnInit() and not this instanceof LocalVariableDeclExpr + or + this = any(ForStmt s).getAnUpdate() + or + // Only applies to SwitchStmt, but not to SwitchExpr, see JLS 17 section 14.11.2 + // TODO: Possibly redundant depending on how https://github.com/github/codeql/issues/8570 is resolved + this = any(SwitchStmt s).getACase().getRuleExpression() + or + // TODO: Workarounds for https://github.com/github/codeql/issues/3605 + exists(LambdaExpr lambda | + this = lambda.getExprBody() and + lambda.asMethod().getReturnType() instanceof VoidType + ) + or + exists(MemberRefExpr memberRef, Method implicitMethod, Method overridden | + implicitMethod = memberRef.asMethod() + | + this.getParent().(ReturnStmt).getEnclosingCallable() = implicitMethod and + // asMethod() has bogus method with wrong return type as result, e.g. `run(): String` (overriding `Runnable.run(): void`) + // Therefore need to check the overridden method + implicitMethod.getSourceDeclaration().overridesOrInstantiates*(overridden) and + overridden.getReturnType() instanceof VoidType + ) + } +} diff --git a/java/ql/lib/semmle/code/java/Maps.qll b/java/ql/lib/semmle/code/java/Maps.qll index 784db84fb98..f768ee3642b 100644 --- a/java/ql/lib/semmle/code/java/Maps.qll +++ b/java/ql/lib/semmle/code/java/Maps.qll @@ -53,7 +53,7 @@ class MapMutation extends MethodAccess { MapMutation() { this.getMethod() instanceof MapMutator } /** Holds if the result of this call is not immediately discarded. */ - predicate resultIsChecked() { not this.getParent() instanceof ExprStmt } + predicate resultIsChecked() { not this instanceof StmtExpr } } /** A method that queries the contents of the map it belongs to without mutating it. */ diff --git a/java/ql/src/Likely Bugs/Statements/ReturnValueIgnored.ql b/java/ql/src/Likely Bugs/Statements/ReturnValueIgnored.ql index 39d6e7fe16b..1c2905c1d61 100644 --- a/java/ql/src/Likely Bugs/Statements/ReturnValueIgnored.ql +++ b/java/ql/src/Likely Bugs/Statements/ReturnValueIgnored.ql @@ -18,7 +18,7 @@ import Chaining predicate checkedMethodCall(MethodAccess ma) { relevantMethodCall(ma, _) and - not ma.getParent() instanceof ExprStmt + not ma instanceof StmtExpr } /** diff --git a/java/ql/src/Violations of Best Practice/Exception Handling/IgnoreExceptionalReturn.ql b/java/ql/src/Violations of Best Practice/Exception Handling/IgnoreExceptionalReturn.ql index cbdaddf3b45..ed712eb2504 100644 --- a/java/ql/src/Violations of Best Practice/Exception Handling/IgnoreExceptionalReturn.ql +++ b/java/ql/src/Violations of Best Practice/Exception Handling/IgnoreExceptionalReturn.ql @@ -45,7 +45,7 @@ predicate unboundedQueue(RefType t) { from MethodAccess ma, SpecialMethod m where - ma.getParent() instanceof ExprStmt and + ma instanceof StmtExpr and m = ma.getMethod() and ( m.isMethod("java.util", "Queue", "offer", 1) and not unboundedQueue(m.getDeclaringType()) diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql b/java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql index 55d51a19a8c..38e2cb79998 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql @@ -21,7 +21,7 @@ private class HostnameVerificationCall extends MethodAccess { } /** Holds if the result of the call is not used. */ - predicate isIgnored() { this = any(ExprStmt es).getExpr() } + predicate isIgnored() { this instanceof StmtExpr } } from HostnameVerificationCall verification diff --git a/java/ql/test/library-tests/StmtExpr/StmtExpr.expected b/java/ql/test/library-tests/StmtExpr/StmtExpr.expected new file mode 100644 index 00000000000..ecb5e338238 --- /dev/null +++ b/java/ql/test/library-tests/StmtExpr/StmtExpr.expected @@ -0,0 +1,14 @@ +| StmtExpr.java:7:9:7:18 | toString(...) | +| StmtExpr.java:13:9:13:13 | ...=... | +| StmtExpr.java:14:9:14:11 | ...++ | +| StmtExpr.java:15:9:15:11 | ++... | +| StmtExpr.java:16:9:16:11 | ...-- | +| StmtExpr.java:17:9:17:11 | --... | +| StmtExpr.java:19:9:19:20 | new Object(...) | +| StmtExpr.java:22:9:22:28 | clone(...) | +| StmtExpr.java:25:14:25:39 | println(...) | +| StmtExpr.java:30:17:30:44 | println(...) | +| StmtExpr.java:45:24:45:33 | toString(...) | +| StmtExpr.java:58:28:58:37 | toString(...) | +| StmtExpr.java:60:13:60:22 | toString(...) | +| StmtExpr.java:66:23:66:36 | toString(...) | diff --git a/java/ql/test/library-tests/StmtExpr/StmtExpr.java b/java/ql/test/library-tests/StmtExpr/StmtExpr.java new file mode 100644 index 00000000000..c35e24ea122 --- /dev/null +++ b/java/ql/test/library-tests/StmtExpr/StmtExpr.java @@ -0,0 +1,68 @@ +package StmtExpr; + +import java.util.function.Supplier; + +class StmtExpr { + void test() { + toString(); + + // LocalVariableDeclarationStatement with init is not a StatementExpression + String s = toString(); + + int i; + i = 0; + i++; + ++i; + i--; + --i; + + new Object(); + // ArrayCreationExpression cannot be a StatementExpression, but a method access + // on it can be + new int[] {}.clone(); + + // for statement init can be StatementExpression + for (System.out.println("init");;) { + break; + } + + // for statement update is StatementExpression + for (;; System.out.println("update")) { + break; + } + + // variable declaration and condition are not StatementExpressions + for (int i1 = 0; i1 < 10;) { } + for (int i1, i2 = 0; i2 < 10;) { } + for (;;) { + break; + } + + // Not a StatementExpression + for (int i2 : new int[] {1}) { } + + switch(1) { + default -> toString(); // StatementExpression + } + // SwitchExpression has no StatementExpression + String s2 = switch(1) { + default -> toString(); + }; + + // Lambda with non-void return type has no StatementExpression + Supplier supplier1 = () -> toString(); + Supplier supplier2 = () -> { + return toString(); + }; + // Lambda with void return type has StatementExpression + Runnable r = () -> toString(); + Runnable r2 = () -> { + toString(); + }; + + // Method reference with non-void return type has no StatementExpression + Supplier supplier3 = StmtExpr::new; + // Method reference with void return type has StatementExpression in implicit method body + Runnable r3 = this::toString; + } +} diff --git a/java/ql/test/library-tests/StmtExpr/StmtExpr.ql b/java/ql/test/library-tests/StmtExpr/StmtExpr.ql new file mode 100644 index 00000000000..c624e738d71 --- /dev/null +++ b/java/ql/test/library-tests/StmtExpr/StmtExpr.ql @@ -0,0 +1,4 @@ +import java + +from StmtExpr e +select e diff --git a/java/ql/test/library-tests/StmtExpr/options b/java/ql/test/library-tests/StmtExpr/options new file mode 100644 index 00000000000..03edcc8fcc0 --- /dev/null +++ b/java/ql/test/library-tests/StmtExpr/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -source 14 -target 14 \ No newline at end of file From 774c811e972f38a363948ed7f663abbb22804a91 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 25 Mar 2022 12:58:19 +0100 Subject: [PATCH 039/171] python: move CSRF concepts inside `HTTP::Server` --- python/ql/lib/semmle/python/Concepts.qll | 140 +++++++++--------- .../lib/semmle/python/frameworks/Django.qll | 4 +- .../CWE-352/CSRFProtectionDisabled.ql | 4 +- .../test/experimental/meta/ConceptsTest.qll | 4 +- 4 files changed, 76 insertions(+), 76 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 01aa16d2094..fe3cad338bb 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -105,76 +105,6 @@ module FileSystemWriteAccess { } } -/** - * A data-flow node that enables or disables Cross-site request forgery protection - * in a global manner. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `CsrfProtectionSetting::Range` instead. - */ -class CsrfProtectionSetting extends DataFlow::Node instanceof CsrfProtectionSetting::Range { - /** - * Gets the boolean value corresponding to if CSRF protection is enabled - * (`true`) or disabled (`false`) by this node. - */ - boolean getVerificationSetting() { result = super.getVerificationSetting() } -} - -/** Provides a class for modeling new CSRF protection setting APIs. */ -module CsrfProtectionSetting { - /** - * A data-flow node that enables or disables Cross-site request forgery protection - * in a global manner. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `CsrfProtectionSetting` instead. - */ - abstract class Range extends DataFlow::Node { - /** - * Gets the boolean value corresponding to if CSRF protection is enabled - * (`true`) or disabled (`false`) by this node. - */ - abstract boolean getVerificationSetting(); - } -} - -/** - * A data-flow node that enables or disables Cross-site request forgery protection - * for a specific part of an application. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `CsrfLocalProtectionSetting::Range` instead. - */ -class CsrfLocalProtectionSetting extends DataFlow::Node instanceof CsrfLocalProtectionSetting::Range { - /** - * Gets a request handler whose CSRF protection is changed. - */ - Function getRequestHandler() { result = super.getRequestHandler() } - - /** Holds if CSRF protection is enabled by this setting */ - predicate csrfEnabled() { super.csrfEnabled() } -} - -/** Provides a class for modeling new CSRF protection setting APIs. */ -module CsrfLocalProtectionSetting { - /** - * A data-flow node that enables or disables Cross-site request forgery protection - * for a specific part of an application. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `CsrfLocalProtectionSetting` instead. - */ - abstract class Range extends DataFlow::Node { - /** - * Gets a request handler whose CSRF protection is changed. - */ - abstract Function getRequestHandler(); - - /** Holds if CSRF protection is enabled by this setting */ - abstract predicate csrfEnabled(); - } -} - /** Provides classes for modeling path-related APIs. */ module Path { /** @@ -956,6 +886,76 @@ module HTTP { abstract DataFlow::Node getValueArg(); } } + + /** + * A data-flow node that enables or disables Cross-site request forgery protection + * in a global manner. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `CsrfProtectionSetting::Range` instead. + */ + class CsrfProtectionSetting extends DataFlow::Node instanceof CsrfProtectionSetting::Range { + /** + * Gets the boolean value corresponding to if CSRF protection is enabled + * (`true`) or disabled (`false`) by this node. + */ + boolean getVerificationSetting() { result = super.getVerificationSetting() } + } + + /** Provides a class for modeling new CSRF protection setting APIs. */ + module CsrfProtectionSetting { + /** + * A data-flow node that enables or disables Cross-site request forgery protection + * in a global manner. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `CsrfProtectionSetting` instead. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets the boolean value corresponding to if CSRF protection is enabled + * (`true`) or disabled (`false`) by this node. + */ + abstract boolean getVerificationSetting(); + } + } + + /** + * A data-flow node that enables or disables Cross-site request forgery protection + * for a specific part of an application. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `CsrfLocalProtectionSetting::Range` instead. + */ + class CsrfLocalProtectionSetting extends DataFlow::Node instanceof CsrfLocalProtectionSetting::Range { + /** + * Gets a request handler whose CSRF protection is changed. + */ + Function getRequestHandler() { result = super.getRequestHandler() } + + /** Holds if CSRF protection is enabled by this setting */ + predicate csrfEnabled() { super.csrfEnabled() } + } + + /** Provides a class for modeling new CSRF protection setting APIs. */ + module CsrfLocalProtectionSetting { + /** + * A data-flow node that enables or disables Cross-site request forgery protection + * for a specific part of an application. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `CsrfLocalProtectionSetting` instead. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets a request handler whose CSRF protection is changed. + */ + abstract Function getRequestHandler(); + + /** Holds if CSRF protection is enabled by this setting */ + abstract predicate csrfEnabled(); + } + } } /** Provides classes for modeling HTTP clients. */ diff --git a/python/ql/lib/semmle/python/frameworks/Django.qll b/python/ql/lib/semmle/python/frameworks/Django.qll index c2852187b48..f8b4272a741 100644 --- a/python/ql/lib/semmle/python/frameworks/Django.qll +++ b/python/ql/lib/semmle/python/frameworks/Django.qll @@ -2320,7 +2320,7 @@ module PrivateDjango { /** * A custom middleware stack */ - private class DjangoSettingsMiddlewareStack extends CsrfProtectionSetting::Range { + private class DjangoSettingsMiddlewareStack extends HTTP::Server::CsrfProtectionSetting::Range { List list; DjangoSettingsMiddlewareStack() { @@ -2356,7 +2356,7 @@ module PrivateDjango { } } - private class DjangoCsrfDecorator extends CsrfLocalProtectionSetting::Range { + private class DjangoCsrfDecorator extends HTTP::Server::CsrfLocalProtectionSetting::Range { string decoratorName; Function function; diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql index e7202a361e5..44353c9b322 100644 --- a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql @@ -14,10 +14,10 @@ import python import semmle.python.Concepts -from CsrfProtectionSetting s +from HTTP::Server::CsrfProtectionSetting s where s.getVerificationSetting() = false and - not exists(CsrfLocalProtectionSetting p | p.csrfEnabled()) and + not exists(HTTP::Server::CsrfLocalProtectionSetting p | p.csrfEnabled()) and // rule out test code as this is a common place to turn off CSRF protection not s.getLocation().getFile().getAbsolutePath().matches("%test%") select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened." diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 339087d50d6..b7fbea26264 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -511,7 +511,7 @@ class CsrfProtectionSettingTest extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and - exists(CsrfProtectionSetting setting | + exists(HTTP::Server::CsrfProtectionSetting setting | location = setting.getLocation() and element = setting.toString() and value = setting.getVerificationSetting().toString() and @@ -527,7 +527,7 @@ class CsrfLocalProtectionSettingTest extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and - exists(CsrfLocalProtectionSetting p | + exists(HTTP::Server::CsrfLocalProtectionSetting p | location = p.getLocation() and element = p.toString() and value = p.getRequestHandler().getName().toString() and From d39410aa2d54edc7f5f680a8d1f4e0f766b5d323 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 25 Mar 2022 13:03:00 +0100 Subject: [PATCH 040/171] python: backport review comment to Ruby --- .../src/queries/security/cwe-352/CSRFProtectionDisabled.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionDisabled.qhelp b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionDisabled.qhelp index 8b5ff38d5a3..7656a676d64 100644 --- a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionDisabled.qhelp +++ b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionDisabled.qhelp @@ -6,7 +6,7 @@

    Cross-site request forgery (CSRF) is a type of vulnerability in which an - attacker is able to force a user carry out an action that the user did + attacker is able to force a user to carry out an action that the user did not intend.

    From 3416f074e8365ea250e5b3abcb1dae4e8a10dc96 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 29 Mar 2022 13:59:04 +0200 Subject: [PATCH 041/171] Update python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql Explain why `TestScope` is not used. Co-authored-by: Rasmus Wriedt Larsen --- python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql index 44353c9b322..24917411fb4 100644 --- a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql @@ -18,6 +18,8 @@ from HTTP::Server::CsrfProtectionSetting s where s.getVerificationSetting() = false and not exists(HTTP::Server::CsrfLocalProtectionSetting p | p.csrfEnabled()) and - // rule out test code as this is a common place to turn off CSRF protection + // rule out test code as this is a common place to turn off CSRF protection. + // We don't use normal `TestScope` to find test files, since we also want to match + // a settings file such as `.../integration-tests/settings.py` not s.getLocation().getFile().getAbsolutePath().matches("%test%") select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened." From 92033047a51018285b081cba1d234b704078d9e3 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Tue, 29 Mar 2022 23:32:33 +0530 Subject: [PATCH 042/171] Python : Add query to detect PAM authorization bypass Using only a call to `pam_authenticate` to check the validity of a login can lead to authorization bypass vulnerabilities. A `pam_authenticate` only verifies the credentials of a user. It does not check if a user has an appropriate authorization to actually login. This means a user with a expired login or a password can still access the system. This PR includes a qhelp describing the issue, a query which detects instances where a call to `pam_acc_mgmt` does not follow a call to `pam_authenticate` and it's corresponding tests. This PR has multiple detections. Some of the public one I can find are : * [CVE-2022-0860](https://nvd.nist.gov/vuln/detail/CVE-2022-0860) found in [cobbler/cobbler](https://www.github.com/cobbler/cobbler) * [fredhutch/motuz](https://www.huntr.dev/bounties/d46f91ca-b8ef-4b67-a79a-2420c4c6d52b/) --- .../Security/CWE-285/PamAuthorization.qhelp | 49 ++++++++++ .../Security/CWE-285/PamAuthorization.ql | 58 +++++++++++ .../Security/CWE-285/PamAuthorizationBad.py | 15 +++ .../Security/CWE-285/PamAuthorizationGood.py | 17 ++++ .../CWE-285/PamAuthorization.expected | 1 + .../Security/CWE-285/PamAuthorization.qlref | 1 + .../query-tests/Security/CWE-285/bad.py | 95 ++++++++++++++++++ .../query-tests/Security/CWE-285/good.py | 97 +++++++++++++++++++ 8 files changed, 333 insertions(+) create mode 100644 python/ql/src/experimental/Security/CWE-285/PamAuthorization.qhelp create mode 100644 python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql create mode 100644 python/ql/src/experimental/Security/CWE-285/PamAuthorizationBad.py create mode 100644 python/ql/src/experimental/Security/CWE-285/PamAuthorizationGood.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.qlref create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-285/bad.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-285/good.py diff --git a/python/ql/src/experimental/Security/CWE-285/PamAuthorization.qhelp b/python/ql/src/experimental/Security/CWE-285/PamAuthorization.qhelp new file mode 100644 index 00000000000..8e0f829f33e --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-285/PamAuthorization.qhelp @@ -0,0 +1,49 @@ + + + +

    + Using only a call to + pam_authenticate + to check the validity of a login can lead to authorization bypass vulnerabilities. +

    +

    + A + pam_authenticate + only verifies the credentials of a user. It does not check if a user has an appropriate authorization to actually login. This means a user with a expired login or a password can still access the system. +

    + +
    + + +

    + A call to + pam_authenticate + should be followed by a call to + pam_acct_mgmt + to check if a user is allowed to login. +

    +
    + + +

    + In the following example, the code only checks the credentials of a user. Hence, in this case, a user expired with expired creds can still login. This can be verified by creating a new user account, expiring it with + chage -E0 `username` + and then trying to log in. +

    + + +

    + This can be avoided by calling + pam_acct_mgmt + call to verify access as has been done in the snippet shown below. +

    + +
    + + +
  • + Man-Page: + pam_acct_mgmt +
  • +
    +
    \ No newline at end of file diff --git a/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql b/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql new file mode 100644 index 00000000000..e67745cceac --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql @@ -0,0 +1,58 @@ +/** + * @name Authorization bypass due to incorrect usage of PAM + * @description Using only the `pam_authenticate` call to check the validity of a login can lead to a authorization bypass. + * @kind problem + * @problem.severity warning + * @id py/pam-auth-bypass + * @tags security + * external/cwe/cwe-285 + */ + +import python +import semmle.python.ApiGraphs +import experimental.semmle.python.Concepts +import semmle.python.dataflow.new.TaintTracking + +private class LibPam extends API::Node { + LibPam() { + exists( + API::Node cdll, API::Node find_library, API::Node libpam, API::CallNode cdll_call, + API::CallNode find_lib_call, StrConst str + | + API::moduleImport("ctypes").getMember("CDLL") = cdll and + find_library = API::moduleImport("ctypes.util").getMember("find_library") and + cdll_call = cdll.getACall() and + find_lib_call = find_library.getACall() and + DataFlow::localFlow(DataFlow::exprNode(str), find_lib_call.getArg(0)) and + str.getText() = "pam" and + cdll_call.getArg(0) = find_lib_call and + libpam = cdll_call.getReturn() + | + libpam = this + ) + } + + override string toString() { result = "libpam" } +} + +class PamAuthCall extends API::Node { + PamAuthCall() { exists(LibPam pam | pam.getMember("pam_authenticate") = this) } + + override string toString() { result = "pam_authenticate" } +} + +class PamActMgt extends API::Node { + PamActMgt() { exists(LibPam pam | pam.getMember("pam_acct_mgmt") = this) } + + override string toString() { result = "pam_acct_mgmt" } +} + +from PamAuthCall p, API::CallNode u, Expr handle +where + u = p.getACall() and + handle = u.asExpr().(Call).getArg(0) and + not exists(PamActMgt pam | + DataFlow::localFlow(DataFlow::exprNode(handle), + DataFlow::exprNode(pam.getACall().asExpr().(Call).getArg(0))) + ) +select u, "This PAM authentication call may be lead to an authorization bypass." diff --git a/python/ql/src/experimental/Security/CWE-285/PamAuthorizationBad.py b/python/ql/src/experimental/Security/CWE-285/PamAuthorizationBad.py new file mode 100644 index 00000000000..3b06156f551 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-285/PamAuthorizationBad.py @@ -0,0 +1,15 @@ +def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True): + libpam = CDLL(find_library("pam")) + pam_authenticate = libpam.pam_authenticate + pam_acct_mgmt = libpam.pam_acct_mgmt + pam_authenticate.restype = c_int + pam_authenticate.argtypes = [PamHandle, c_int] + pam_acct_mgmt.restype = c_int + pam_acct_mgmt.argtypes = [PamHandle, c_int] + + handle = PamHandle() + conv = PamConv(my_conv, 0) + retval = pam_start(service, username, byref(conv), byref(handle)) + + retval = pam_authenticate(handle, 0) + return retval == 0 \ No newline at end of file diff --git a/python/ql/src/experimental/Security/CWE-285/PamAuthorizationGood.py b/python/ql/src/experimental/Security/CWE-285/PamAuthorizationGood.py new file mode 100644 index 00000000000..0f047c6ac65 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-285/PamAuthorizationGood.py @@ -0,0 +1,17 @@ +def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True): + libpam = CDLL(find_library("pam")) + pam_authenticate = libpam.pam_authenticate + pam_acct_mgmt = libpam.pam_acct_mgmt + pam_authenticate.restype = c_int + pam_authenticate.argtypes = [PamHandle, c_int] + pam_acct_mgmt.restype = c_int + pam_acct_mgmt.argtypes = [PamHandle, c_int] + + handle = PamHandle() + conv = PamConv(my_conv, 0) + retval = pam_start(service, username, byref(conv), byref(handle)) + + retval = pam_authenticate(handle, 0) + if retval == 0: + retval = pam_acct_mgmt(handle, 0) + return retval == 0 \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected b/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected new file mode 100644 index 00000000000..52c4c8ac669 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected @@ -0,0 +1 @@ +| bad.py:92:18:92:44 | ControlFlowNode for pam_authenticate() | This PAM authentication call may be lead to an authorization bypass. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.qlref b/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.qlref new file mode 100644 index 00000000000..38fac298b1e --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-285/PamAuthorization.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-285/bad.py b/python/ql/test/experimental/query-tests/Security/CWE-285/bad.py new file mode 100644 index 00000000000..84527d6f6fb --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-285/bad.py @@ -0,0 +1,95 @@ +from ctypes import CDLL, POINTER, Structure, CFUNCTYPE, cast, byref, sizeof +from ctypes import c_void_p, c_size_t, c_char_p, c_char, c_int +from ctypes import memmove +from ctypes.util import find_library + +class PamHandle(Structure): + _fields_ = [ ("handle", c_void_p) ] + + def __init__(self): + Structure.__init__(self) + self.handle = 0 + +class PamMessage(Structure): + """wrapper class for pam_message structure""" + _fields_ = [ ("msg_style", c_int), ("msg", c_char_p) ] + + def __repr__(self): + return "" % (self.msg_style, self.msg) + +class PamResponse(Structure): + """wrapper class for pam_response structure""" + _fields_ = [ ("resp", c_char_p), ("resp_retcode", c_int) ] + + def __repr__(self): + return "" % (self.resp_retcode, self.resp) + +conv_func = CFUNCTYPE(c_int, c_int, POINTER(POINTER(PamMessage)), POINTER(POINTER(PamResponse)), c_void_p) + +class PamConv(Structure): + """wrapper class for pam_conv structure""" + _fields_ = [ ("conv", conv_func), ("appdata_ptr", c_void_p) ] + +# Various constants +PAM_PROMPT_ECHO_OFF = 1 +PAM_PROMPT_ECHO_ON = 2 +PAM_ERROR_MSG = 3 +PAM_TEXT_INFO = 4 +PAM_REINITIALIZE_CRED = 8 + +libc = CDLL(find_library("c")) +libpam = CDLL(find_library("pam")) + +calloc = libc.calloc +calloc.restype = c_void_p +calloc.argtypes = [c_size_t, c_size_t] + +# bug #6 (@NIPE-SYSTEMS), some libpam versions don't include this function +if hasattr(libpam, 'pam_end'): + pam_end = libpam.pam_end + pam_end.restype = c_int + pam_end.argtypes = [PamHandle, c_int] + +pam_start = libpam.pam_start +pam_start.restype = c_int +pam_start.argtypes = [c_char_p, c_char_p, POINTER(PamConv), POINTER(PamHandle)] + +pam_setcred = libpam.pam_setcred +pam_setcred.restype = c_int +pam_setcred.argtypes = [PamHandle, c_int] + +pam_strerror = libpam.pam_strerror +pam_strerror.restype = c_char_p +pam_strerror.argtypes = [PamHandle, c_int] + +pam_authenticate = libpam.pam_authenticate +pam_authenticate.restype = c_int +pam_authenticate.argtypes = [PamHandle, c_int] + +pam_acct_mgmt = libpam.pam_acct_mgmt +pam_acct_mgmt.restype = c_int +pam_acct_mgmt.argtypes = [PamHandle, c_int] + +class pam(): + code = 0 + reason = None + + def __init__(self): + pass + + def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True): + @conv_func + def my_conv(n_messages, messages, p_response, app_data): + return 0 + + + cpassword = c_char_p(password) + + handle = PamHandle() + conv = PamConv(my_conv, 0) + retval = pam_start(service, username, byref(conv), byref(handle)) + + retval = pam_authenticate(handle, 0) + auth_success = retval == 0 + + return auth_success \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/Security/CWE-285/good.py b/python/ql/test/experimental/query-tests/Security/CWE-285/good.py new file mode 100644 index 00000000000..e9996c770ed --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-285/good.py @@ -0,0 +1,97 @@ +from ctypes import CDLL, POINTER, Structure, CFUNCTYPE, cast, byref, sizeof +from ctypes import c_void_p, c_size_t, c_char_p, c_char, c_int +from ctypes import memmove +from ctypes.util import find_library + +class PamHandle(Structure): + _fields_ = [ ("handle", c_void_p) ] + + def __init__(self): + Structure.__init__(self) + self.handle = 0 + +class PamMessage(Structure): + """wrapper class for pam_message structure""" + _fields_ = [ ("msg_style", c_int), ("msg", c_char_p) ] + + def __repr__(self): + return "" % (self.msg_style, self.msg) + +class PamResponse(Structure): + """wrapper class for pam_response structure""" + _fields_ = [ ("resp", c_char_p), ("resp_retcode", c_int) ] + + def __repr__(self): + return "" % (self.resp_retcode, self.resp) + +conv_func = CFUNCTYPE(c_int, c_int, POINTER(POINTER(PamMessage)), POINTER(POINTER(PamResponse)), c_void_p) + +class PamConv(Structure): + """wrapper class for pam_conv structure""" + _fields_ = [ ("conv", conv_func), ("appdata_ptr", c_void_p) ] + +# Various constants +PAM_PROMPT_ECHO_OFF = 1 +PAM_PROMPT_ECHO_ON = 2 +PAM_ERROR_MSG = 3 +PAM_TEXT_INFO = 4 +PAM_REINITIALIZE_CRED = 8 + +libc = CDLL(find_library("c")) +libpam = CDLL(find_library("pam")) + +calloc = libc.calloc +calloc.restype = c_void_p +calloc.argtypes = [c_size_t, c_size_t] + +# bug #6 (@NIPE-SYSTEMS), some libpam versions don't include this function +if hasattr(libpam, 'pam_end'): + pam_end = libpam.pam_end + pam_end.restype = c_int + pam_end.argtypes = [PamHandle, c_int] + +pam_start = libpam.pam_start +pam_start.restype = c_int +pam_start.argtypes = [c_char_p, c_char_p, POINTER(PamConv), POINTER(PamHandle)] + +pam_setcred = libpam.pam_setcred +pam_setcred.restype = c_int +pam_setcred.argtypes = [PamHandle, c_int] + +pam_strerror = libpam.pam_strerror +pam_strerror.restype = c_char_p +pam_strerror.argtypes = [PamHandle, c_int] + +pam_authenticate = libpam.pam_authenticate +pam_authenticate.restype = c_int +pam_authenticate.argtypes = [PamHandle, c_int] + +pam_acct_mgmt = libpam.pam_acct_mgmt +pam_acct_mgmt.restype = c_int +pam_acct_mgmt.argtypes = [PamHandle, c_int] + +class pam(): + code = 0 + reason = None + + def __init__(self): + pass + + def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True): + @conv_func + def my_conv(n_messages, messages, p_response, app_data): + return 0 + + + cpassword = c_char_p(password) + + handle = PamHandle() + conv = PamConv(my_conv, 0) + retval = pam_start(service, username, byref(conv), byref(handle)) + + retval = pam_authenticate(handle, 0) + if retval == 0: + retval = pam_acct_mgmt(handle, 0) + auth_success = retval == 0 + + return auth_success \ No newline at end of file From 65907c97620e2824ffbd008db54a98d9ee1a1060 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 24 Mar 2022 14:13:12 +0100 Subject: [PATCH 043/171] Python: Copy Xxe/XmlBomb queries from JS After internal discussion, these will replace the `XmlEntityInjection` query, so we can have separate severities on DoS and the other (more serious) attacks. Note: These clearly don't work, since they are verbatim copies of the JS code, but I split it into multiple commits to clearly highlight what changes were made. --- .../Security/NEW/CWE-611/Xxe.qhelp | 57 ++++++++++++++++++ .../experimental/Security/NEW/CWE-611/Xxe.ql | 23 +++++++ .../Security/NEW/CWE-611/examples/Xxe.js | 7 +++ .../Security/NEW/CWE-611/examples/XxeGood.js | 7 +++ .../Security/NEW/CWE-776/XmlBomb.qhelp | 60 +++++++++++++++++++ .../Security/NEW/CWE-776/XmlBomb.ql | 23 +++++++ .../Security/NEW/CWE-776/examples/XmlBomb.js | 10 ++++ .../NEW/CWE-776/examples/XmlBombGood.js | 10 ++++ .../dataflow/XmlBombCustomizations.qll | 49 +++++++++++++++ .../python/security/dataflow/XmlBombQuery.qll | 27 +++++++++ .../security/dataflow/XxeCustomizations.qll | 52 ++++++++++++++++ .../python/security/dataflow/XxeQuery.qll | 27 +++++++++ 12 files changed, 352 insertions(+) create mode 100644 python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp create mode 100644 python/ql/src/experimental/Security/NEW/CWE-611/Xxe.ql create mode 100644 python/ql/src/experimental/Security/NEW/CWE-611/examples/Xxe.js create mode 100644 python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.js create mode 100644 python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.qhelp create mode 100644 python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.ql create mode 100644 python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBomb.js create mode 100644 python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.js create mode 100644 python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll create mode 100644 python/ql/src/experimental/semmle/python/security/dataflow/XmlBombQuery.qll create mode 100644 python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll create mode 100644 python/ql/src/experimental/semmle/python/security/dataflow/XxeQuery.qll diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp b/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp new file mode 100644 index 00000000000..1e859eb121f --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp @@ -0,0 +1,57 @@ + + + + +

    +Parsing untrusted XML files with a weakly configured XML parser may lead to an +XML External Entity (XXE) attack. This type of attack uses external entity references +to access arbitrary files on a system, carry out denial-of-service (DoS) attacks, or server-side +request forgery. Even when the result of parsing is not returned to the user, DoS attacks are still possible +and out-of-band data retrieval techniques may allow attackers to steal sensitive data. +

    +
    + + +

    +The easiest way to prevent XXE attacks is to disable external entity handling when +parsing untrusted data. How this is done depends on the library being used. Note that some +libraries, such as recent versions of libxml, disable entity expansion by default, +so unless you have explicitly enabled entity expansion, no further action needs to be taken. +

    +
    + + +

    +The following example uses the libxml XML parser to parse a string xmlSrc. +If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since +the parser is invoked with the noent option set to true: +

    + + +

    +To guard against XXE attacks, the noent option should be omitted or set to +false. This means that no entity expansion is undertaken at all, not even for standard +internal entities such as &amp; or &gt;. If desired, these +entities can be expanded in a separate step using utility functions provided by libraries such +as underscore, +lodash or +he. +

    + +
    + + +
  • +OWASP: +XML External Entity (XXE) Processing. +
  • +
  • +Timothy Morgen: +XML Schema, DTD, and Entity Attacks. +
  • +
  • +Timur Yunusov, Alexey Osipov: +XML Out-Of-Band Data Retrieval. +
  • +
    +
    diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.ql b/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.ql new file mode 100644 index 00000000000..01e518b6df7 --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.ql @@ -0,0 +1,23 @@ +/** + * @name XML external entity expansion + * @description Parsing user input as an XML document with external + * entity expansion is vulnerable to XXE attacks. + * @kind path-problem + * @problem.severity error + * @security-severity 9.1 + * @precision high + * @id js/xxe + * @tags security + * external/cwe/cwe-611 + * external/cwe/cwe-827 + */ + +import javascript +import semmle.javascript.security.dataflow.XxeQuery +import DataFlow::PathGraph + +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, + "A $@ is parsed as XML without guarding against external entity expansion.", source.getNode(), + "user-provided value" diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/examples/Xxe.js b/python/ql/src/experimental/Security/NEW/CWE-611/examples/Xxe.js new file mode 100644 index 00000000000..99fa02cc42f --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-611/examples/Xxe.js @@ -0,0 +1,7 @@ +const app = require("express")(), + libxml = require("libxmljs"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + doc = libxml.parseXml(xmlSrc, { noent: true }); +}); diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.js b/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.js new file mode 100644 index 00000000000..8317dcac98f --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.js @@ -0,0 +1,7 @@ +const app = require("express")(), + libxml = require("libxmljs"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + doc = libxml.parseXml(xmlSrc); +}); diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.qhelp b/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.qhelp new file mode 100644 index 00000000000..c0714b3f96f --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.qhelp @@ -0,0 +1,60 @@ + + + + +

    +Parsing untrusted XML files with a weakly configured XML parser may be vulnerable to +denial-of-service (DoS) attacks exploiting uncontrolled internal entity expansion. +

    +

    +In XML, so-called internal entities are a mechanism for introducing an abbreviation +for a piece of text or part of a document. When a parser that has been configured +to expand entities encounters a reference to an internal entity, it replaces the entity +by the data it represents. The replacement text may itself contain other entity references, +which are expanded recursively. This means that entity expansion can increase document size +dramatically. +

    +

    +If untrusted XML is parsed with entity expansion enabled, a malicious attacker could +submit a document that contains very deeply nested entity definitions, causing the parser +to take a very long time or use large amounts of memory. This is sometimes called an +XML bomb attack. +

    +
    + + +

    +The safest way to prevent XML bomb attacks is to disable entity expansion when parsing untrusted +data. How this is done depends on the library being used. Note that some libraries, such as +recent versions of libxmljs (though not its SAX parser API), disable entity expansion +by default, so unless you have explicitly enabled entity expansion, no further action is needed. +

    +
    + + +

    +The following example uses the XML parser provided by the node-expat package to +parse a string xmlSrc. If that string is from an untrusted source, this code may be +vulnerable to a DoS attack, since node-expat expands internal entities by default: +

    + + +

    +At the time of writing, node-expat does not provide a way of controlling entity +expansion, but the example could be rewritten to use the sax package instead, +which only expands standard entities such as &amp;: +

    + +
    + + +
  • +Wikipedia: +Billion Laughs. +
  • +
  • +Bryan Sullivan: +Security Briefs - XML Denial of Service Attacks and Defenses. +
  • +
    +
    diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.ql b/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.ql new file mode 100644 index 00000000000..c340eee68cc --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.ql @@ -0,0 +1,23 @@ +/** + * @name XML internal entity expansion + * @description Parsing user input as an XML document with arbitrary internal + * entity expansion is vulnerable to denial-of-service attacks. + * @kind path-problem + * @problem.severity warning + * @security-severity 7.5 + * @precision high + * @id js/xml-bomb + * @tags security + * external/cwe/cwe-776 + * external/cwe/cwe-400 + */ + +import javascript +import semmle.javascript.security.dataflow.XmlBombQuery +import DataFlow::PathGraph + +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, + "A $@ is parsed as XML without guarding against uncontrolled entity expansion.", source.getNode(), + "user-provided value" diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBomb.js b/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBomb.js new file mode 100644 index 00000000000..f72902a5304 --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBomb.js @@ -0,0 +1,10 @@ +const app = require("express")(), + expat = require("node-expat"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + parser = new expat.Parser(); + parser.on("startElement", handleStart); + parser.on("text", handleText); + parser.write(xmlSrc); +}); diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.js b/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.js new file mode 100644 index 00000000000..a8c5bc97e63 --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.js @@ -0,0 +1,10 @@ +const app = require("express")(), + sax = require("sax"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + parser = sax.parser(true); + parser.onopentag = handleStart; + parser.ontext = handleText; + parser.write(xmlSrc); +}); diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll new file mode 100644 index 00000000000..1d159b057ad --- /dev/null +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll @@ -0,0 +1,49 @@ +/** + * Provides default sources, sinks and sanitizers for reasoning about + * XML-bomb vulnerabilities, as well as extension points for adding + * your own. + */ + +import javascript +import semmle.javascript.security.dataflow.DOM + +module XmlBomb { + /** + * A data flow source for XML-bomb vulnerabilities. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for XML-bomb vulnerabilities. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A sanitizer for XML-bomb vulnerabilities. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** A source of remote user input, considered as a flow source for XML bomb vulnerabilities. */ + class RemoteFlowSourceAsSource extends Source { + RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } + } + + /** + * An access to `document.location`, considered as a flow source for XML bomb vulnerabilities. + */ + class LocationAsSource extends Source, DataFlow::ValueNode { + LocationAsSource() { isLocation(astNode) } + } + + /** + * A call to an XML parser that performs internal entity expansion, viewed + * as a data flow sink for XML-bomb vulnerabilities. + */ + class XmlParsingWithEntityResolution extends Sink, DataFlow::ValueNode { + XmlParsingWithEntityResolution() { + exists(XML::ParserInvocation parse | astNode = parse.getSourceArgument() | + parse.resolvesEntities(XML::InternalEntity()) + ) + } + } +} diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombQuery.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombQuery.qll new file mode 100644 index 00000000000..951b927f86e --- /dev/null +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombQuery.qll @@ -0,0 +1,27 @@ +/** + * Provides a taint tracking configuration for reasoning about + * XML-bomb vulnerabilities. + * + * Note, for performance reasons: only import this file if + * `XmlBomb::Configuration` is needed, otherwise + * `XmlBombCustomizations` should be imported instead. + */ + +import javascript +import XmlBombCustomizations::XmlBomb + +/** + * A taint-tracking configuration for reasoning about XML-bomb vulnerabilities. + */ +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "XmlBomb" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node node) { + super.isSanitizer(node) or + node instanceof Sanitizer + } +} diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll new file mode 100644 index 00000000000..4e7bb5e730c --- /dev/null +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll @@ -0,0 +1,52 @@ +/** + * Provides default sources, sinks and sanitizers for reasoning about + * XML External Entity (XXE) vulnerabilities, as well as extension + * points for adding your own. + */ + +import javascript +import semmle.javascript.security.dataflow.DOM + +module Xxe { + /** + * A data flow source for XXE vulnerabilities. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for XXE vulnerabilities. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A sanitizer for XXE vulnerabilities. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** A source of remote user input, considered as a flow source for XXE vulnerabilities. */ + class RemoteFlowSourceAsSource extends Source { + RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } + } + + /** + * An access to `document.location`, considered as a flow source for XXE vulnerabilities. + */ + class LocationAsSource extends Source, DataFlow::ValueNode { + LocationAsSource() { isLocation(astNode) } + } + + /** + * A call to an XML parser that performs external entity expansion, viewed + * as a data flow sink for XXE vulnerabilities. + */ + class XmlParsingWithExternalEntityResolution extends Sink, DataFlow::ValueNode { + XmlParsingWithExternalEntityResolution() { + exists(XML::ParserInvocation parse | astNode = parse.getSourceArgument() | + parse.resolvesEntities(XML::ExternalEntity(_)) + or + parse.resolvesEntities(XML::ParameterEntity(true)) and + parse.resolvesEntities(XML::InternalEntity()) + ) + } + } +} diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeQuery.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XxeQuery.qll new file mode 100644 index 00000000000..82d3fb4f6cc --- /dev/null +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XxeQuery.qll @@ -0,0 +1,27 @@ +/** + * Provides a taint tracking configuration for reasoning about XML + * External Entity (XXE) vulnerabilities. + * + * Note, for performance reasons: only import this file if + * `Xxe::Configuration` is needed, otherwise `XxeCustomizations` + * should be imported instead. + */ + +import javascript +import XxeCustomizations::Xxe + +/** + * A taint-tracking configuration for reasoning about XXE vulnerabilities. + */ +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "Xxe" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node node) { + super.isSanitizer(node) or + node instanceof Sanitizer + } +} From e45f9d69ccb44a2109518f3c8334e21f5c193a43 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 24 Mar 2022 14:15:54 +0100 Subject: [PATCH 044/171] Python: Adjust Xxe/XmlBomb for Python I changed a few QLdocs so they fit the style we have used in Python... although I surely do regret having introduced a new style for how these QLDocs look :D --- .../experimental/Security/NEW/CWE-611/Xxe.ql | 6 ++-- .../Security/NEW/CWE-776/XmlBomb.ql | 6 ++-- .../dataflow/XmlBombCustomizations.qll | 31 +++++++++-------- .../python/security/dataflow/XmlBombQuery.qll | 11 +++--- .../security/dataflow/XxeCustomizations.qll | 34 +++++++++---------- .../python/security/dataflow/XxeQuery.qll | 13 +++---- 6 files changed, 51 insertions(+), 50 deletions(-) diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.ql b/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.ql index 01e518b6df7..f706ea6e909 100644 --- a/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.ql +++ b/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.ql @@ -6,14 +6,14 @@ * @problem.severity error * @security-severity 9.1 * @precision high - * @id js/xxe + * @id py/xxe * @tags security * external/cwe/cwe-611 * external/cwe/cwe-827 */ -import javascript -import semmle.javascript.security.dataflow.XxeQuery +import python +import experimental.semmle.python.security.dataflow.XxeQuery import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.ql b/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.ql index c340eee68cc..2a1ea5916c4 100644 --- a/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.ql +++ b/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.ql @@ -6,14 +6,14 @@ * @problem.severity warning * @security-severity 7.5 * @precision high - * @id js/xml-bomb + * @id py/xml-bomb * @tags security * external/cwe/cwe-776 * external/cwe/cwe-400 */ -import javascript -import semmle.javascript.security.dataflow.XmlBombQuery +import python +import experimental.semmle.python.security.dataflow.XmlBombQuery import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll index 1d159b057ad..66a16a4494a 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll @@ -1,12 +1,18 @@ /** - * Provides default sources, sinks and sanitizers for reasoning about - * XML-bomb vulnerabilities, as well as extension points for adding - * your own. + * Provides default sources, sinks and sanitizers for detecting + * "XML bomb" + * vulnerabilities, as well as extension points for adding your own. */ -import javascript -import semmle.javascript.security.dataflow.DOM +private import python +private import semmle.python.dataflow.new.DataFlow +private import experimental.semmle.python.Concepts +private import semmle.python.dataflow.new.RemoteFlowSources +/** + * Provides default sources, sinks and sanitizers for detecting "XML bomb" + * vulnerabilities, as well as extension points for adding your own. + */ module XmlBomb { /** * A data flow source for XML-bomb vulnerabilities. @@ -28,21 +34,16 @@ module XmlBomb { RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } } - /** - * An access to `document.location`, considered as a flow source for XML bomb vulnerabilities. - */ - class LocationAsSource extends Source, DataFlow::ValueNode { - LocationAsSource() { isLocation(astNode) } - } - /** * A call to an XML parser that performs internal entity expansion, viewed * as a data flow sink for XML-bomb vulnerabilities. */ - class XmlParsingWithEntityResolution extends Sink, DataFlow::ValueNode { + class XmlParsingWithEntityResolution extends Sink { XmlParsingWithEntityResolution() { - exists(XML::ParserInvocation parse | astNode = parse.getSourceArgument() | - parse.resolvesEntities(XML::InternalEntity()) + exists(ExperimentalXML::XMLParsing parsing, ExperimentalXML::XMLVulnerabilityKind kind | + (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and + parsing.vulnerableTo(kind) and + this = parsing.getAnInput() ) } } diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombQuery.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombQuery.qll index 951b927f86e..d0c0b85d84f 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombQuery.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombQuery.qll @@ -1,17 +1,18 @@ /** - * Provides a taint tracking configuration for reasoning about - * XML-bomb vulnerabilities. + * Provides a taint-tracking configuration for detecting "XML bomb" vulnerabilities. * * Note, for performance reasons: only import this file if - * `XmlBomb::Configuration` is needed, otherwise + * `Configuration` is needed, otherwise * `XmlBombCustomizations` should be imported instead. */ -import javascript +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking import XmlBombCustomizations::XmlBomb /** - * A taint-tracking configuration for reasoning about XML-bomb vulnerabilities. + * A taint-tracking configuration for detecting "XML bomb" vulnerabilities. */ class Configuration extends TaintTracking::Configuration { Configuration() { this = "XmlBomb" } diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll index 4e7bb5e730c..b2992dd335f 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll @@ -1,12 +1,18 @@ /** - * Provides default sources, sinks and sanitizers for reasoning about - * XML External Entity (XXE) vulnerabilities, as well as extension - * points for adding your own. + * Provides default sources, sinks and sanitizers for detecting + * "XML External Entity (XXE)" + * vulnerabilities, as well as extension points for adding your own. */ -import javascript -import semmle.javascript.security.dataflow.DOM +private import python +private import semmle.python.dataflow.new.DataFlow +private import experimental.semmle.python.Concepts +private import semmle.python.dataflow.new.RemoteFlowSources +/** + * Provides default sources, sinks and sanitizers for detecting "XML External Entity (XXE)" + * vulnerabilities, as well as extension points for adding your own. + */ module Xxe { /** * A data flow source for XXE vulnerabilities. @@ -28,24 +34,16 @@ module Xxe { RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } } - /** - * An access to `document.location`, considered as a flow source for XXE vulnerabilities. - */ - class LocationAsSource extends Source, DataFlow::ValueNode { - LocationAsSource() { isLocation(astNode) } - } - /** * A call to an XML parser that performs external entity expansion, viewed * as a data flow sink for XXE vulnerabilities. */ - class XmlParsingWithExternalEntityResolution extends Sink, DataFlow::ValueNode { + class XmlParsingWithExternalEntityResolution extends Sink { XmlParsingWithExternalEntityResolution() { - exists(XML::ParserInvocation parse | astNode = parse.getSourceArgument() | - parse.resolvesEntities(XML::ExternalEntity(_)) - or - parse.resolvesEntities(XML::ParameterEntity(true)) and - parse.resolvesEntities(XML::InternalEntity()) + exists(ExperimentalXML::XMLParsing parsing, ExperimentalXML::XMLVulnerabilityKind kind | + kind.isXxe() and + parsing.vulnerableTo(kind) and + this = parsing.getAnInput() ) } } diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeQuery.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XxeQuery.qll index 82d3fb4f6cc..dd2409f2a3c 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XxeQuery.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XxeQuery.qll @@ -1,17 +1,18 @@ /** - * Provides a taint tracking configuration for reasoning about XML - * External Entity (XXE) vulnerabilities. + * Provides a taint-tracking configuration for detecting "XML External Entity (XXE)" vulnerabilities. * * Note, for performance reasons: only import this file if - * `Xxe::Configuration` is needed, otherwise `XxeCustomizations` - * should be imported instead. + * `Configuration` is needed, otherwise + * `XxeCustomizations` should be imported instead. */ -import javascript +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking import XxeCustomizations::Xxe /** - * A taint-tracking configuration for reasoning about XXE vulnerabilities. + * A taint-tracking configuration for detecting "XML External Entity (XXE)" vulnerabilities. */ class Configuration extends TaintTracking::Configuration { Configuration() { this = "Xxe" } From 91795b857756a4912e6a280e4e53f65f4fbaf76a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 24 Mar 2022 14:16:38 +0100 Subject: [PATCH 045/171] Python: Add simple test of Xxe/XmlBomb Note that most of the testing happens in the framework specific tests, with an inline-expectation test --- .../Security/CWE-611-Xxe/Xxe.expected | 20 +++++++++++++ .../Security/CWE-611-Xxe/Xxe.qlref | 1 + .../query-tests/Security/CWE-611-Xxe/test.py | 30 +++++++++++++++++++ .../Security/CWE-776-XmlBomb/XmlBomb.expected | 12 ++++++++ .../Security/CWE-776-XmlBomb/XmlBomb.qlref | 1 + .../Security/CWE-776-XmlBomb/test.py | 30 +++++++++++++++++++ 6 files changed, 94 insertions(+) create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.qlref create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/test.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/test.py diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.expected b/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.expected new file mode 100644 index 00000000000..004369d79cf --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.expected @@ -0,0 +1,20 @@ +edges +| test.py:8:19:8:25 | ControlFlowNode for request | test.py:8:19:8:30 | ControlFlowNode for Attribute | +| test.py:8:19:8:30 | ControlFlowNode for Attribute | test.py:8:19:8:45 | ControlFlowNode for Subscript | +| test.py:8:19:8:45 | ControlFlowNode for Subscript | test.py:9:34:9:44 | ControlFlowNode for xml_content | +| test.py:19:19:19:25 | ControlFlowNode for request | test.py:19:19:19:30 | ControlFlowNode for Attribute | +| test.py:19:19:19:30 | ControlFlowNode for Attribute | test.py:19:19:19:45 | ControlFlowNode for Subscript | +| test.py:19:19:19:45 | ControlFlowNode for Subscript | test.py:30:34:30:44 | ControlFlowNode for xml_content | +nodes +| test.py:8:19:8:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| test.py:8:19:8:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:8:19:8:45 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| test.py:9:34:9:44 | ControlFlowNode for xml_content | semmle.label | ControlFlowNode for xml_content | +| test.py:19:19:19:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| test.py:19:19:19:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:19:19:19:45 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| test.py:30:34:30:44 | ControlFlowNode for xml_content | semmle.label | ControlFlowNode for xml_content | +subpaths +#select +| test.py:9:34:9:44 | ControlFlowNode for xml_content | test.py:8:19:8:25 | ControlFlowNode for request | test.py:9:34:9:44 | ControlFlowNode for xml_content | A $@ is parsed as XML without guarding against external entity expansion. | test.py:8:19:8:25 | ControlFlowNode for request | user-provided value | +| test.py:30:34:30:44 | ControlFlowNode for xml_content | test.py:19:19:19:25 | ControlFlowNode for request | test.py:30:34:30:44 | ControlFlowNode for xml_content | A $@ is parsed as XML without guarding against external entity expansion. | test.py:19:19:19:25 | ControlFlowNode for request | user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.qlref b/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.qlref new file mode 100644 index 00000000000..f8a07d7d2ee --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.qlref @@ -0,0 +1 @@ +experimental/Security/NEW/CWE-611/Xxe.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/test.py b/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/test.py new file mode 100644 index 00000000000..d9181c4cf34 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/test.py @@ -0,0 +1,30 @@ +from flask import Flask, request +import lxml.etree + +app = Flask(__name__) + +@app.route("/vuln-handler") +def vuln_handler(): + xml_content = request.args['xml_content'] + return lxml.etree.fromstring(xml_content).text + +@app.route("/safe-handler") +def safe_handler(): + xml_content = request.args['xml_content'] + parser = lxml.etree.XMLParser(resolve_entities=False) + return lxml.etree.fromstring(xml_content, parser=parser).text + +@app.route("/super-vuln-handler") +def super_vuln_handler(): + xml_content = request.args['xml_content'] + parser = lxml.etree.XMLParser( + # allows XXE + resolve_entities=True, + # allows remote XXE + no_network=False, + # together with `no_network=False`, allows DTD-retrival + load_dtd=True, + # allows DoS attacks + huge_tree=True, + ) + return lxml.etree.fromstring(xml_content, parser=parser).text diff --git a/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.expected b/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.expected new file mode 100644 index 00000000000..15c439d0761 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.expected @@ -0,0 +1,12 @@ +edges +| test.py:19:19:19:25 | ControlFlowNode for request | test.py:19:19:19:30 | ControlFlowNode for Attribute | +| test.py:19:19:19:30 | ControlFlowNode for Attribute | test.py:19:19:19:45 | ControlFlowNode for Subscript | +| test.py:19:19:19:45 | ControlFlowNode for Subscript | test.py:30:34:30:44 | ControlFlowNode for xml_content | +nodes +| test.py:19:19:19:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| test.py:19:19:19:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:19:19:19:45 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| test.py:30:34:30:44 | ControlFlowNode for xml_content | semmle.label | ControlFlowNode for xml_content | +subpaths +#select +| test.py:30:34:30:44 | ControlFlowNode for xml_content | test.py:19:19:19:25 | ControlFlowNode for request | test.py:30:34:30:44 | ControlFlowNode for xml_content | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | test.py:19:19:19:25 | ControlFlowNode for request | user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref b/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref new file mode 100644 index 00000000000..5eadbb1f26f --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref @@ -0,0 +1 @@ +experimental/Security/NEW/CWE-776/XmlBomb.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/test.py b/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/test.py new file mode 100644 index 00000000000..d9181c4cf34 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/test.py @@ -0,0 +1,30 @@ +from flask import Flask, request +import lxml.etree + +app = Flask(__name__) + +@app.route("/vuln-handler") +def vuln_handler(): + xml_content = request.args['xml_content'] + return lxml.etree.fromstring(xml_content).text + +@app.route("/safe-handler") +def safe_handler(): + xml_content = request.args['xml_content'] + parser = lxml.etree.XMLParser(resolve_entities=False) + return lxml.etree.fromstring(xml_content, parser=parser).text + +@app.route("/super-vuln-handler") +def super_vuln_handler(): + xml_content = request.args['xml_content'] + parser = lxml.etree.XMLParser( + # allows XXE + resolve_entities=True, + # allows remote XXE + no_network=False, + # together with `no_network=False`, allows DTD-retrival + load_dtd=True, + # allows DoS attacks + huge_tree=True, + ) + return lxml.etree.fromstring(xml_content, parser=parser).text From a1d88e39a77f4c16ca0e292ca5e6311828745b2e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 24 Mar 2022 15:36:20 +0100 Subject: [PATCH 046/171] Python: Adjust XXE PoC for newer lxml versions Which doesn't raise that syntax error (at least not on my laptop) --- .../experimental/library-tests/frameworks/XML/poc/PoC.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py b/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py index adcace1aa0a..77d6c032683 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py @@ -361,11 +361,7 @@ class TestLxml: hit_xxe = False parser = lxml.etree.XMLParser() - try: - root = lxml.etree.fromstring(remote_xxe, parser=parser) - assert False - except lxml.etree.XMLSyntaxError as e: - assert "Failure to process entity remote_xxe" in str(e) + root = lxml.etree.fromstring(remote_xxe, parser=parser) assert hit_xxe == False @staticmethod From 57b97804283545dbe986c019660ae5171ba8e7ed Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 24 Mar 2022 15:37:14 +0100 Subject: [PATCH 047/171] Python: XXE: Add example of exfiltrating data through dtd-retrival --- .../library-tests/frameworks/XML/poc/PoC.py | 32 ++++++++++++++++++- .../library-tests/frameworks/XML/poc/flag | 2 +- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py b/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py index 77d6c032683..b4cb2faf304 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py @@ -70,6 +70,10 @@ dtd_retrieval = f""" bar """ +exfiltrate_through_dtd_retrieval = f""" + %xxe; ]> +""" + # ============================================================================== # other setup @@ -95,6 +99,22 @@ def test_xxe(): hit_xxe = True return "ok" +@app.route("/exfiltrate-through.dtd") +def exfiltrate_through_dtd(): + return f""" +"> +%eval; +%exfiltrate; + """ + +exfiltrated_data = None +@app.route("/exfiltrate-data") +def exfiltrate_data(): + from flask import request + global exfiltrated_data + exfiltrated_data = request.args["data"] + return "ok" + def run_app(): app.run(host=HOST, port=PORT) @@ -346,7 +366,7 @@ class TestLxml: parser = lxml.etree.XMLParser() root = lxml.etree.fromstring(local_xxe, parser=parser) assert root.tag == "test" - assert root.text == "SECRET_FLAG\n", root.text + assert root.text == "SECRET_FLAG", root.text @staticmethod def test_local_xxe_disabled(): @@ -412,6 +432,16 @@ class TestLxml: pass assert hit_dtd == False + @staticmethod + def test_exfiltrate_through_dtd(): + # note that this only works when the data to exfiltrate does not contain a newline :| + global exfiltrated_data + exfiltrated_data = None + parser = lxml.etree.XMLParser(load_dtd=True, no_network=False) + with pytest.raises(lxml.etree.XMLSyntaxError): + lxml.etree.fromstring(exfiltrate_through_dtd_retrieval, parser=parser) + + assert exfiltrated_data == "SECRET_FLAG" # ============================================================================== diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/poc/flag b/python/ql/test/experimental/library-tests/frameworks/XML/poc/flag index 45c9436ee9f..b8bd6838774 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/poc/flag +++ b/python/ql/test/experimental/library-tests/frameworks/XML/poc/flag @@ -1 +1 @@ -SECRET_FLAG +SECRET_FLAG \ No newline at end of file From 769f5691d08dd8288e4eb6432e163b0a53c8ac21 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 29 Mar 2022 17:18:06 +0200 Subject: [PATCH 048/171] Python: Add taint for `StringIO` and `BytesIO` --- .../2022-03-29-add-taint-for-StringIO.md | 4 ++ .../lib/semmle/python/frameworks/Stdlib.qll | 58 +++++++++++++++++++ .../frameworks/stdlib/io_test.py | 47 +++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 python/ql/lib/change-notes/2022-03-29-add-taint-for-StringIO.md create mode 100644 python/ql/test/library-tests/frameworks/stdlib/io_test.py diff --git a/python/ql/lib/change-notes/2022-03-29-add-taint-for-StringIO.md b/python/ql/lib/change-notes/2022-03-29-add-taint-for-StringIO.md new file mode 100644 index 00000000000..7857e6f9ca6 --- /dev/null +++ b/python/ql/lib/change-notes/2022-03-29-add-taint-for-StringIO.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added taint propagation for `io.StringIO` and `io.BytesIO`. This addition was originally [submitted as part of an experimental query by @jorgectf](https://github.com/github/codeql/pull/6112). diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 22dce5427ae..234a8802f0f 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3116,6 +3116,64 @@ private module StdlibPrivate { result in [this.getArg(0), this.getArgByName("path")] } } + + // --------------------------------------------------------------------------- + // io + // --------------------------------------------------------------------------- + /** + * Provides models for the `io.StringIO`/`io.BytesIO` classes + * + * See https://docs.python.org/3.10/library/io.html#io.StringIO. + */ + module StringIO { + /** Gets a reference to the `io.StringIO` class. */ + private API::Node classRef() { + result = API::moduleImport("io").getMember(["StringIO", "BytesIO"]) + } + + /** + * A source of instances of `io.StringIO`/`io.BytesIO`, extend this class to model new instances. + * + * This can include instantiations of the class, return values from function + * calls, or a special parameter that will be set when functions are called by an external + * library. + * + * Use the predicate `StringIO::instance()` to get references to instances of `io.StringIO`. + */ + abstract class InstanceSource extends Stdlib::FileLikeObject::InstanceSource { } + + /** A direct instantiation of `io.StringIO`/`io.BytesIO`. */ + private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode { + ClassInstantiation() { this = classRef().getACall() } + + DataFlow::Node getInitialValue() { + result = this.getArg(0) + or + // `initial_value` for StringIO, `initial_bytes` for BytesIO + result = this.getArgByName(["initial_value", "initial_bytes"]) + } + } + + /** Gets a reference to an instance of `io.StringIO`/`io.BytesIO`. */ + private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { + t.start() and + result instanceof InstanceSource + or + exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) + } + + /** Gets a reference to an instance of `io.StringIO`/`io.BytesIO`. */ + DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } + + /** + * Extra taint propagation for `io.StringIO`/`io.BytesIO`. + */ + private class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep { + override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + nodeTo.(ClassInstantiation).getInitialValue() = nodeFrom + } + } + } } // --------------------------------------------------------------------------- diff --git a/python/ql/test/library-tests/frameworks/stdlib/io_test.py b/python/ql/test/library-tests/frameworks/stdlib/io_test.py new file mode 100644 index 00000000000..98d60445e1c --- /dev/null +++ b/python/ql/test/library-tests/frameworks/stdlib/io_test.py @@ -0,0 +1,47 @@ +from io import StringIO, BytesIO + +TAINTED_STRING = "TS" +TAINTED_BYTES = b"TB" + +def ensure_tainted(*args): + print("ensure_tainted") + for arg in args: + print("", repr(arg)) + + +def test_stringio(): + ts = TAINTED_STRING + + x = StringIO() + x.write(ts) + x.seek(0) + + ensure_tainted( + StringIO(ts), # $ tainted + StringIO(initial_value=ts), # $ tainted + x, # $ tainted + + x.read(), # $ tainted + StringIO(ts).read(), # $ tainted + ) + + +def test_bytesio(): + tb = TAINTED_BYTES + + x = BytesIO() + x.write(tb) + x.seek(0) + + ensure_tainted( + BytesIO(tb), # $ tainted + BytesIO(initial_bytes=tb), # $ tainted + x, # $ tainted + + x.read(), # $ tainted + BytesIO(tb).read(), # $ tainted + ) + + +test_stringio() +test_bytesio() From c3653378671f7e8c39c20993f16f64224945bf97 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 29 Mar 2022 11:20:38 +0200 Subject: [PATCH 049/171] Python: Delete `XmlEntityInjection.ql` Kept the test of SimpleXmlRpcServer, and kept the qhelp so it can be used to write the new qhelp files --- .../src/experimental/Security/CWE-611/XXE.xml | 4 - .../Security/CWE-611/XmlEntityInjection.py | 25 ------ .../Security/CWE-611/XmlEntityInjection.ql | 31 ------- .../{CWE-611 => NEW}/XmlEntityInjection.qhelp | 0 .../security/dataflow/XmlEntityInjection.qll | 28 ------ .../XmlEntityInjectionCustomizations.qll | 86 ------------------- .../SimpleXmlRpcServer.expected | 0 .../SimpleXmlRpcServer.qlref | 0 .../xmlrpc_server.py | 0 .../CWE-611/XmlEntityInjection.expected | 27 ------ .../Security/CWE-611/XmlEntityInjection.qlref | 1 - .../query-tests/Security/CWE-611/test.py | 30 ------- 12 files changed, 232 deletions(-) delete mode 100644 python/ql/src/experimental/Security/CWE-611/XXE.xml delete mode 100644 python/ql/src/experimental/Security/CWE-611/XmlEntityInjection.py delete mode 100644 python/ql/src/experimental/Security/CWE-611/XmlEntityInjection.ql rename python/ql/src/experimental/Security/{CWE-611 => NEW}/XmlEntityInjection.qhelp (100%) delete mode 100644 python/ql/src/experimental/semmle/python/security/dataflow/XmlEntityInjection.qll delete mode 100644 python/ql/src/experimental/semmle/python/security/dataflow/XmlEntityInjectionCustomizations.qll rename python/ql/test/experimental/query-tests/Security/{CWE-611 => CWE-611-SimpleXmlRpcServer}/SimpleXmlRpcServer.expected (100%) rename python/ql/test/experimental/query-tests/Security/{CWE-611 => CWE-611-SimpleXmlRpcServer}/SimpleXmlRpcServer.qlref (100%) rename python/ql/test/experimental/query-tests/Security/{CWE-611 => CWE-611-SimpleXmlRpcServer}/xmlrpc_server.py (100%) delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-611/XmlEntityInjection.expected delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-611/XmlEntityInjection.qlref delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-611/test.py diff --git a/python/ql/src/experimental/Security/CWE-611/XXE.xml b/python/ql/src/experimental/Security/CWE-611/XXE.xml deleted file mode 100644 index ddd196f2f13..00000000000 --- a/python/ql/src/experimental/Security/CWE-611/XXE.xml +++ /dev/null @@ -1,4 +0,0 @@ - -]> -&xxe; \ No newline at end of file diff --git a/python/ql/src/experimental/Security/CWE-611/XmlEntityInjection.py b/python/ql/src/experimental/Security/CWE-611/XmlEntityInjection.py deleted file mode 100644 index 0e9eec933d7..00000000000 --- a/python/ql/src/experimental/Security/CWE-611/XmlEntityInjection.py +++ /dev/null @@ -1,25 +0,0 @@ -from flask import request, Flask -import lxml.etree -import xml.etree.ElementTree - -app = Flask(__name__) - -# BAD -@app.route("/bad") -def bad(): - xml_content = request.args['xml_content'] - - parser = lxml.etree.XMLParser() - parsed_xml = xml.etree.ElementTree.fromstring(xml_content, parser=parser) - - return parsed_xml.text - -# GOOD -@app.route("/good") -def good(): - xml_content = request.args['xml_content'] - - parser = lxml.etree.XMLParser(resolve_entities=False) - parsed_xml = xml.etree.ElementTree.fromstring(xml_content, parser=parser) - - return parsed_xml.text \ No newline at end of file diff --git a/python/ql/src/experimental/Security/CWE-611/XmlEntityInjection.ql b/python/ql/src/experimental/Security/CWE-611/XmlEntityInjection.ql deleted file mode 100644 index 922ca346b17..00000000000 --- a/python/ql/src/experimental/Security/CWE-611/XmlEntityInjection.ql +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @name XML Entity injection - * @description User input should not be parsed allowing the injection of entities. - * @kind path-problem - * @problem.severity error - * @id py/xml-entity-injection - * @tags security - * external/cwe/cwe-611 - * external/cwe/cwe-776 - * external/cwe/cwe-827 - */ - -// determine precision above -import python -import experimental.semmle.python.security.dataflow.XmlEntityInjection -import DataFlow::PathGraph - -from - XmlEntityInjection::XmlEntityInjectionConfiguration config, DataFlow::PathNode source, - DataFlow::PathNode sink, string kinds -where - config.hasFlowPath(source, sink) and - kinds = - strictconcat(string kind | - kind = sink.getNode().(XmlEntityInjection::Sink).getVulnerableKind() - | - kind, ", " - ) -select sink.getNode(), source, sink, - "$@ XML input is constructed from a $@ and is vulnerable to: " + kinds + ".", sink.getNode(), - "This", source.getNode(), "user-provided value" diff --git a/python/ql/src/experimental/Security/CWE-611/XmlEntityInjection.qhelp b/python/ql/src/experimental/Security/NEW/XmlEntityInjection.qhelp similarity index 100% rename from python/ql/src/experimental/Security/CWE-611/XmlEntityInjection.qhelp rename to python/ql/src/experimental/Security/NEW/XmlEntityInjection.qhelp diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlEntityInjection.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlEntityInjection.qll deleted file mode 100644 index 35220e153d1..00000000000 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XmlEntityInjection.qll +++ /dev/null @@ -1,28 +0,0 @@ -import python -import experimental.semmle.python.Concepts -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking -import semmle.python.dataflow.new.RemoteFlowSources -import semmle.python.dataflow.new.BarrierGuards - -module XmlEntityInjection { - import XmlEntityInjectionCustomizations::XmlEntityInjection - - class XmlEntityInjectionConfiguration extends TaintTracking::Configuration { - XmlEntityInjectionConfiguration() { this = "XmlEntityInjectionConfiguration" } - - override predicate isSource(DataFlow::Node source) { - source instanceof RemoteFlowSourceAsSource - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { - guard instanceof SanitizerGuard - } - - override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - any(AdditionalTaintStep s).step(nodeFrom, nodeTo) - } - } -} diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlEntityInjectionCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlEntityInjectionCustomizations.qll deleted file mode 100644 index e420c738a97..00000000000 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XmlEntityInjectionCustomizations.qll +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Provides default sources, sinks and sanitizers for detecting - * "ldap injection" - * vulnerabilities, as well as extension points for adding your own. - */ - -private import python -private import semmle.python.dataflow.new.DataFlow -private import experimental.semmle.python.Concepts -private import semmle.python.dataflow.new.RemoteFlowSources -private import semmle.python.dataflow.new.BarrierGuards -private import semmle.python.ApiGraphs - -/** - * Provides default sources, sinks and sanitizers for detecting "xml injection" - * vulnerabilities, as well as extension points for adding your own. - */ -module XmlEntityInjection { - /** - * A data flow source for "xml injection" vulnerabilities. - */ - abstract class Source extends DataFlow::Node { } - - /** - * A data flow sink for "xml injection" vulnerabilities. - */ - abstract class Sink extends DataFlow::Node { - /** Gets the kind of XML injection that this sink is vulnerable to. */ - abstract string getVulnerableKind(); - } - - /** - * A sanitizer guard for "xml injection" vulnerabilities. - */ - abstract class SanitizerGuard extends DataFlow::BarrierGuard { } - - /** - * A unit class for adding additional taint steps. - * - * Extend this class to add additional taint steps that should apply to `XmlEntityInjection` - * taint configuration. - */ - class AdditionalTaintStep extends Unit { - /** - * Holds if the step from `nodeFrom` to `nodeTo` should be considered a taint - * step for `XmlEntityInjection` configuration. - */ - abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo); - } - - /** - * An input to a direct XML parsing function, considered as a flow sink. - * - * See `XML::XMLParsing`. - */ - class XMLParsingInputAsSink extends Sink { - ExperimentalXML::XMLParsing xmlParsing; - - XMLParsingInputAsSink() { this = xmlParsing.getAnInput() } - - override string getVulnerableKind() { xmlParsing.vulnerableTo(result) } - } - - /** - * A source of remote user input, considered as a flow source. - */ - class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { } - - /** - * A comparison with a constant string, considered as a sanitizer-guard. - */ - class StringConstCompareAsSanitizerGuard extends SanitizerGuard, StringConstCompare { } - - /** - * A taint step for `io`'s `StringIO` and `BytesIO` methods. - */ - class IoAdditionalTaintStep extends AdditionalTaintStep { - override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - exists(DataFlow::CallCfgNode ioCalls | - ioCalls = API::moduleImport("io").getMember(["StringIO", "BytesIO"]).getACall() and - nodeFrom = ioCalls.getArg(0) and - nodeTo = ioCalls - ) - } - } -} diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611/SimpleXmlRpcServer.expected b/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.expected similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-611/SimpleXmlRpcServer.expected rename to python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.expected diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611/SimpleXmlRpcServer.qlref b/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.qlref similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-611/SimpleXmlRpcServer.qlref rename to python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.qlref diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611/xmlrpc_server.py b/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/xmlrpc_server.py similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-611/xmlrpc_server.py rename to python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/xmlrpc_server.py diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611/XmlEntityInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-611/XmlEntityInjection.expected deleted file mode 100644 index 25594b4ddaa..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-611/XmlEntityInjection.expected +++ /dev/null @@ -1,27 +0,0 @@ -edges -| test.py:8:19:8:25 | ControlFlowNode for request | test.py:8:19:8:30 | ControlFlowNode for Attribute | -| test.py:8:19:8:30 | ControlFlowNode for Attribute | test.py:8:19:8:45 | ControlFlowNode for Subscript | -| test.py:8:19:8:45 | ControlFlowNode for Subscript | test.py:9:34:9:44 | ControlFlowNode for xml_content | -| test.py:13:19:13:25 | ControlFlowNode for request | test.py:13:19:13:30 | ControlFlowNode for Attribute | -| test.py:13:19:13:30 | ControlFlowNode for Attribute | test.py:13:19:13:45 | ControlFlowNode for Subscript | -| test.py:13:19:13:45 | ControlFlowNode for Subscript | test.py:15:34:15:44 | ControlFlowNode for xml_content | -| test.py:19:19:19:25 | ControlFlowNode for request | test.py:19:19:19:30 | ControlFlowNode for Attribute | -| test.py:19:19:19:30 | ControlFlowNode for Attribute | test.py:19:19:19:45 | ControlFlowNode for Subscript | -| test.py:19:19:19:45 | ControlFlowNode for Subscript | test.py:30:34:30:44 | ControlFlowNode for xml_content | -nodes -| test.py:8:19:8:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:8:19:8:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:8:19:8:45 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| test.py:9:34:9:44 | ControlFlowNode for xml_content | semmle.label | ControlFlowNode for xml_content | -| test.py:13:19:13:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:13:19:13:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:13:19:13:45 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| test.py:15:34:15:44 | ControlFlowNode for xml_content | semmle.label | ControlFlowNode for xml_content | -| test.py:19:19:19:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:19:19:19:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:19:19:19:45 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| test.py:30:34:30:44 | ControlFlowNode for xml_content | semmle.label | ControlFlowNode for xml_content | -subpaths -#select -| test.py:9:34:9:44 | ControlFlowNode for xml_content | test.py:8:19:8:25 | ControlFlowNode for request | test.py:9:34:9:44 | ControlFlowNode for xml_content | $@ XML input is constructed from a $@ and is vulnerable to: XXE. | test.py:9:34:9:44 | ControlFlowNode for xml_content | This | test.py:8:19:8:25 | ControlFlowNode for request | user-provided value | -| test.py:30:34:30:44 | ControlFlowNode for xml_content | test.py:19:19:19:25 | ControlFlowNode for request | test.py:30:34:30:44 | ControlFlowNode for xml_content | $@ XML input is constructed from a $@ and is vulnerable to: Billion Laughs, DTD retrieval, Quadratic Blowup, XXE. | test.py:30:34:30:44 | ControlFlowNode for xml_content | This | test.py:19:19:19:25 | ControlFlowNode for request | user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611/XmlEntityInjection.qlref b/python/ql/test/experimental/query-tests/Security/CWE-611/XmlEntityInjection.qlref deleted file mode 100644 index 36a7c8845fb..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-611/XmlEntityInjection.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE-611/XmlEntityInjection.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611/test.py b/python/ql/test/experimental/query-tests/Security/CWE-611/test.py deleted file mode 100644 index d9181c4cf34..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-611/test.py +++ /dev/null @@ -1,30 +0,0 @@ -from flask import Flask, request -import lxml.etree - -app = Flask(__name__) - -@app.route("/vuln-handler") -def vuln_handler(): - xml_content = request.args['xml_content'] - return lxml.etree.fromstring(xml_content).text - -@app.route("/safe-handler") -def safe_handler(): - xml_content = request.args['xml_content'] - parser = lxml.etree.XMLParser(resolve_entities=False) - return lxml.etree.fromstring(xml_content, parser=parser).text - -@app.route("/super-vuln-handler") -def super_vuln_handler(): - xml_content = request.args['xml_content'] - parser = lxml.etree.XMLParser( - # allows XXE - resolve_entities=True, - # allows remote XXE - no_network=False, - # together with `no_network=False`, allows DTD-retrival - load_dtd=True, - # allows DoS attacks - huge_tree=True, - ) - return lxml.etree.fromstring(xml_content, parser=parser).text From b00766b054d1b58a06dce48bd631a5b0eaacb7b7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 29 Mar 2022 13:51:00 +0200 Subject: [PATCH 050/171] Python: Adjust XXE qhelp and remove the old copy, we don't need it anymore :) --- .../Security/NEW/CWE-611/Xxe.qhelp | 39 ++++++++++----- .../Security/NEW/CWE-611/examples/Xxe.js | 7 --- .../Security/NEW/CWE-611/examples/XxeBad.py | 10 ++++ .../Security/NEW/CWE-611/examples/XxeGood.js | 7 --- .../Security/NEW/CWE-611/examples/XxeGood.py | 11 +++++ .../Security/NEW/XmlEntityInjection.qhelp | 48 ------------------- .../library-tests/frameworks/XML/poc/PoC.py | 11 +++++ 7 files changed, 58 insertions(+), 75 deletions(-) delete mode 100644 python/ql/src/experimental/Security/NEW/CWE-611/examples/Xxe.js create mode 100644 python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeBad.py delete mode 100644 python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.js create mode 100644 python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.py delete mode 100644 python/ql/src/experimental/Security/NEW/XmlEntityInjection.qhelp diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp b/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp index 1e859eb121f..7254e292309 100644 --- a/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp +++ b/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp @@ -15,29 +15,34 @@ and out-of-band data retrieval techniques may allow attackers to steal sensitive

    The easiest way to prevent XXE attacks is to disable external entity handling when parsing untrusted data. How this is done depends on the library being used. Note that some -libraries, such as recent versions of libxml, disable entity expansion by default, +libraries, such as recent versions of the XML libraries in the standard library of Python 3, +disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action needs to be taken.

    + +

    +We recommend using the defusedxml +PyPI package, which has been created to prevent XML attacks (both XXE and XML bombs). +

    -The following example uses the libxml XML parser to parse a string xmlSrc. -If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since -the parser is invoked with the noent option set to true: +The following example uses the lxml XML parser to parse a string +xml_src. That string is from an untrusted source, so this code is +vulnerable to an XXE attack, since the +default parser from lxml.etree allows local external entities to be resolved.

    - +

    -To guard against XXE attacks, the noent option should be omitted or set to -false. This means that no entity expansion is undertaken at all, not even for standard -internal entities such as &amp; or &gt;. If desired, these -entities can be expanded in a separate step using utility functions provided by libraries such -as underscore, -lodash or -he. +To guard against XXE attacks with the lxml library, you should create a +parser with resolve_entities set to false. This means that no +entity expansion is undertaken, althuogh standard predefined entities such as +&gt;, for writing > inside the text of an XML element, +are still allowed.

    - +
    @@ -53,5 +58,13 @@ Timothy Morgen: Timur Yunusov, Alexey Osipov: XML Out-Of-Band Data Retrieval. +
  • +Python 3 standard library: +XML Vulnerabilities. +
  • +
  • +Python 2 standard library: +XML Vulnerabilities. +
  • diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/examples/Xxe.js b/python/ql/src/experimental/Security/NEW/CWE-611/examples/Xxe.js deleted file mode 100644 index 99fa02cc42f..00000000000 --- a/python/ql/src/experimental/Security/NEW/CWE-611/examples/Xxe.js +++ /dev/null @@ -1,7 +0,0 @@ -const app = require("express")(), - libxml = require("libxmljs"); - -app.post("upload", (req, res) => { - let xmlSrc = req.body, - doc = libxml.parseXml(xmlSrc, { noent: true }); -}); diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeBad.py b/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeBad.py new file mode 100644 index 00000000000..4b2121ab4a6 --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeBad.py @@ -0,0 +1,10 @@ +from flask import Flask, request +import lxml.etree + +app = Flask(__name__) + +@app.post("/upload") +def upload(): + xml_src = request.get_data() + doc = lxml.etree.fromstring(xml_src) + return lxml.etree.tostring(doc) diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.js b/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.js deleted file mode 100644 index 8317dcac98f..00000000000 --- a/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.js +++ /dev/null @@ -1,7 +0,0 @@ -const app = require("express")(), - libxml = require("libxmljs"); - -app.post("upload", (req, res) => { - let xmlSrc = req.body, - doc = libxml.parseXml(xmlSrc); -}); diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.py b/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.py new file mode 100644 index 00000000000..20844032fa3 --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.py @@ -0,0 +1,11 @@ +from flask import Flask, request +import lxml.etree + +app = Flask(__name__) + +@app.post("/upload") +def upload(): + xml_src = request.get_data() + parser = lxml.etree.XMLParser(resolve_entities=False) + doc = lxml.etree.fromstring(xml_src, parser=parser) + return lxml.etree.tostring(doc) diff --git a/python/ql/src/experimental/Security/NEW/XmlEntityInjection.qhelp b/python/ql/src/experimental/Security/NEW/XmlEntityInjection.qhelp deleted file mode 100644 index 6da1bf1d306..00000000000 --- a/python/ql/src/experimental/Security/NEW/XmlEntityInjection.qhelp +++ /dev/null @@ -1,48 +0,0 @@ - - - - -

    -Parsing untrusted XML files with a weakly configured XML parser may lead to attacks such as XML External Entity (XXE), -Billion Laughs, Quadratic Blowup and DTD retrieval. -This type of attack uses external entity references to access arbitrary files on a system, carry out denial of -service, or server side request forgery. Even when the result of parsing is not returned to the user, out-of-band -data retrieval techniques may allow attackers to steal sensitive data. Denial of services can also be carried out -in this situation. -

    -
    - - -

    -Use defusedxml, a Python package aimed -to prevent any potentially malicious operation. -

    -
    - - -

    -The following example calls xml.etree.ElementTree.fromstring using a parser (lxml.etree.XMLParser) -that is not safely configured on untrusted data, and is therefore inherently unsafe. -

    - -

    -Providing an input (xml_content) like the following XML content against /bad, the request response would contain the contents of -/etc/passwd. -

    - -
    - - -
  • Python 3 XML Vulnerabilities.
  • -
  • Python 2 XML Vulnerabilities.
  • -
  • Python XML Parsing.
  • -
  • OWASP vulnerability description: XML External Entity (XXE) Processing.
  • -
  • OWASP guidance on parsing xml files: XXE Prevention Cheat Sheet.
  • -
  • Paper by Timothy Morgen: XML Schema, DTD, and Entity Attacks
  • -
  • Out-of-band data retrieval: Timur Yunusov & Alexey Osipov, Black hat EU 2013: XML Out-Of-Band Data Retrieval.
  • -
  • Denial of service attack (Billion laughs): Billion Laughs.
  • -
    - -
    diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py b/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py index b4cb2faf304..a4de65084ae 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py @@ -74,6 +74,10 @@ exfiltrate_through_dtd_retrieval = f""" %xxe; ]> """ +predefined_entity_xml = """ +< +""" + # ============================================================================== # other setup @@ -443,6 +447,13 @@ class TestLxml: assert exfiltrated_data == "SECRET_FLAG" + @staticmethod + def test_predefined_entity(): + parser = lxml.etree.XMLParser(resolve_entities=False) + root = lxml.etree.fromstring(predefined_entity_xml, parser=parser) + assert root.tag == "test" + assert root.text == "<" + # ============================================================================== import xmltodict From 56b9c891d85636c543bf9529dd7b191908248be7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 29 Mar 2022 15:30:04 +0200 Subject: [PATCH 051/171] Python: Adjust `XmlBomb.qhelp` from JS --- .../Security/NEW/CWE-776/XmlBomb.qhelp | 36 +++++++++++++------ .../Security/NEW/CWE-776/examples/XmlBomb.js | 10 ------ .../NEW/CWE-776/examples/XmlBombBad.py | 10 ++++++ .../NEW/CWE-776/examples/XmlBombGood.js | 10 ------ .../NEW/CWE-776/examples/XmlBombGood.py | 10 ++++++ 5 files changed, 45 insertions(+), 31 deletions(-) delete mode 100644 python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBomb.js create mode 100644 python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombBad.py delete mode 100644 python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.js create mode 100644 python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.py diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.qhelp b/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.qhelp index c0714b3f96f..f20dd526fdd 100644 --- a/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.qhelp +++ b/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.qhelp @@ -25,26 +25,32 @@ to take a very long time or use large amounts of memory. This is sometimes calle

    The safest way to prevent XML bomb attacks is to disable entity expansion when parsing untrusted -data. How this is done depends on the library being used. Note that some libraries, such as -recent versions of libxmljs (though not its SAX parser API), disable entity expansion -by default, so unless you have explicitly enabled entity expansion, no further action is needed. +data. Whether this can be done depends on the library being used. Note that some libraries, such as +lxml, have measures enabled by default to prevent such DoS XML attacks, so +unless you have explicitly set huge_tree to True, no further action is needed. +

    + +

    +We recommend using the defusedxml +PyPI package, which has been created to prevent XML attacks (both XXE and XML bombs).

    -The following example uses the XML parser provided by the node-expat package to -parse a string xmlSrc. If that string is from an untrusted source, this code may be -vulnerable to a DoS attack, since node-expat expands internal entities by default: +The following example uses the xml.etree XML parser provided by the Python standard library to +parse a string xml_src. That string is from an untrusted source, so this code is be +vulnerable to a DoS attack, since the xml.etree XML parser expands internal entities by default:

    - +

    -At the time of writing, node-expat does not provide a way of controlling entity -expansion, but the example could be rewritten to use the sax package instead, -which only expands standard entities such as &amp;: +It is not possible to guard against internal entity expansion with +xml.etree, so to guard against these attacks, the following example uses +the defusedxml +PyPI package instead, which is not exposed to such internal entity expansion attacks.

    - +
    @@ -56,5 +62,13 @@ Wikipedia: Bryan Sullivan: Security Briefs - XML Denial of Service Attacks and Defenses. +
  • +Python 3 standard library: +XML Vulnerabilities. +
  • +
  • +Python 2 standard library: +XML Vulnerabilities. +
  • diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBomb.js b/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBomb.js deleted file mode 100644 index f72902a5304..00000000000 --- a/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBomb.js +++ /dev/null @@ -1,10 +0,0 @@ -const app = require("express")(), - expat = require("node-expat"); - -app.post("upload", (req, res) => { - let xmlSrc = req.body, - parser = new expat.Parser(); - parser.on("startElement", handleStart); - parser.on("text", handleText); - parser.write(xmlSrc); -}); diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombBad.py b/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombBad.py new file mode 100644 index 00000000000..d52054d9492 --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombBad.py @@ -0,0 +1,10 @@ +from flask import Flask, request +import xml.etree.ElementTree as ET + +app = Flask(__name__) + +@app.post("/upload") +def upload(): + xml_src = request.get_data() + doc = ET.fromstring(xml_src) + return ET.tostring(doc) diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.js b/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.js deleted file mode 100644 index a8c5bc97e63..00000000000 --- a/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.js +++ /dev/null @@ -1,10 +0,0 @@ -const app = require("express")(), - sax = require("sax"); - -app.post("upload", (req, res) => { - let xmlSrc = req.body, - parser = sax.parser(true); - parser.onopentag = handleStart; - parser.ontext = handleText; - parser.write(xmlSrc); -}); diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.py b/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.py new file mode 100644 index 00000000000..5e4261e35da --- /dev/null +++ b/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.py @@ -0,0 +1,10 @@ +from flask import Flask, request +import defusedxml.ElementTree as ET + +app = Flask(__name__) + +@app.post("/upload") +def upload(): + xml_src = request.get_data() + doc = ET.fromstring(xml_src) + return ET.tostring(doc) From 9caf4be21be7370a0317ae44205dfb35a5169073 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 29 Mar 2022 15:33:57 +0200 Subject: [PATCH 052/171] Python: Add PortSwigger link to `Xxe.qhelp` I found this resource quite good myself at least :) --- python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp b/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp index 7254e292309..19bbc955fd6 100644 --- a/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp +++ b/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp @@ -66,5 +66,9 @@ Python 3 standard library: Python 2 standard library: XML Vulnerabilities. +
  • +PortSwigger: +XML external entity (XXE) injection. +
  • From e005a5c0ab7409ebb6fb0002cdc7ab11a1b54bd1 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 29 Mar 2022 15:50:24 +0200 Subject: [PATCH 053/171] Python: Promote `XMLParsing` concept --- python/ql/lib/semmle/python/Concepts.qll | 62 +++++++++++++++++ .../experimental/semmle/python/Concepts.qll | 68 ------------------- .../semmle/python/frameworks/Xml.qll | 4 +- .../dataflow/XmlBombCustomizations.qll | 5 +- .../security/dataflow/XxeCustomizations.qll | 5 +- .../XML/ExperimentalXmlConceptsTests.ql | 2 +- 6 files changed, 70 insertions(+), 76 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index a768f29795c..3d83ec100a5 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -550,6 +550,68 @@ module XML { abstract string getName(); } } + + /** + * A kind of XML vulnerability. + * + * See overview of kinds at https://pypi.org/project/defusedxml/#python-xml-libraries + */ + class XMLVulnerabilityKind extends string { + XMLVulnerabilityKind() { + this in ["Billion Laughs", "Quadratic Blowup", "XXE", "DTD retrieval"] + } + + /** Holds for Billion Laughs vulnerability kind. */ + predicate isBillionLaughs() { this = "Billion Laughs" } + + /** Holds for Quadratic Blowup vulnerability kind. */ + predicate isQuadraticBlowup() { this = "Quadratic Blowup" } + + /** Holds for XXE vulnerability kind. */ + predicate isXxe() { this = "XXE" } + + /** Holds for DTD retrieval vulnerability kind. */ + predicate isDtdRetrieval() { this = "DTD retrieval" } + } + + /** + * A data-flow node that parses XML. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `XMLParsing` instead. + */ + class XMLParsing extends DataFlow::Node instanceof XMLParsing::Range { + /** + * Gets the argument containing the content to parse. + */ + DataFlow::Node getAnInput() { result = super.getAnInput() } + + /** + * Holds if this XML parsing is vulnerable to `kind`. + */ + predicate vulnerableTo(XMLVulnerabilityKind kind) { super.vulnerableTo(kind) } + } + + /** Provides classes for modeling XML parsing APIs. */ + module XMLParsing { + /** + * A data-flow node that parses XML. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `XMLParsing` instead. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets the argument containing the content to parse. + */ + abstract DataFlow::Node getAnInput(); + + /** + * Holds if this XML parsing is vulnerable to `kind`. + */ + abstract predicate vulnerableTo(XMLVulnerabilityKind kind); + } + } } /** Provides classes for modeling LDAP-related APIs. */ diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll index 6fdba4d3627..09b44d95e89 100644 --- a/python/ql/src/experimental/semmle/python/Concepts.qll +++ b/python/ql/src/experimental/semmle/python/Concepts.qll @@ -14,74 +14,6 @@ private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.TaintTracking private import experimental.semmle.python.Frameworks -/** - * Since there is both XML module in normal and experimental Concepts, - * we have to rename the experimental module as this. - */ -module ExperimentalXML { - /** - * A kind of XML vulnerability. - * - * See https://pypi.org/project/defusedxml/#python-xml-libraries - */ - class XMLVulnerabilityKind extends string { - XMLVulnerabilityKind() { - this in ["Billion Laughs", "Quadratic Blowup", "XXE", "DTD retrieval"] - } - - /** Holds for Billion Laughs vulnerability kind. */ - predicate isBillionLaughs() { this = "Billion Laughs" } - - /** Holds for Quadratic Blowup vulnerability kind. */ - predicate isQuadraticBlowup() { this = "Quadratic Blowup" } - - /** Holds for XXE vulnerability kind. */ - predicate isXxe() { this = "XXE" } - - /** Holds for DTD retrieval vulnerability kind. */ - predicate isDtdRetrieval() { this = "DTD retrieval" } - } - - /** - * A data-flow node that parses XML. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `XMLParsing` instead. - */ - class XMLParsing extends DataFlow::Node instanceof XMLParsing::Range { - /** - * Gets the argument containing the content to parse. - */ - DataFlow::Node getAnInput() { result = super.getAnInput() } - - /** - * Holds if this XML parsing is vulnerable to `kind`. - */ - predicate vulnerableTo(XMLVulnerabilityKind kind) { super.vulnerableTo(kind) } - } - - /** Provides classes for modeling XML parsing APIs. */ - module XMLParsing { - /** - * A data-flow node that parses XML. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `XMLParsing` instead. - */ - abstract class Range extends DataFlow::Node { - /** - * Gets the argument containing the content to parse. - */ - abstract DataFlow::Node getAnInput(); - - /** - * Holds if this XML parsing is vulnerable to `kind`. - */ - abstract predicate vulnerableTo(XMLVulnerabilityKind kind); - } - } -} - /** Provides classes for modeling LDAP query execution-related APIs. */ module LdapQuery { /** diff --git a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll index a2f36f66f2e..87aa236804d 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll @@ -5,11 +5,9 @@ private import python private import semmle.python.dataflow.new.DataFlow -private import experimental.semmle.python.Concepts +private import semmle.python.Concepts private import semmle.python.ApiGraphs -module XML = ExperimentalXML; - private module XmlEtree { /** * Provides models for `xml.etree` parsers diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll index 66a16a4494a..a4cbfe61821 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll @@ -6,7 +6,8 @@ private import python private import semmle.python.dataflow.new.DataFlow -private import experimental.semmle.python.Concepts +private import semmle.python.Concepts +import experimental.semmle.python.frameworks.Xml // needed until modeling have been promoted private import semmle.python.dataflow.new.RemoteFlowSources /** @@ -40,7 +41,7 @@ module XmlBomb { */ class XmlParsingWithEntityResolution extends Sink { XmlParsingWithEntityResolution() { - exists(ExperimentalXML::XMLParsing parsing, ExperimentalXML::XMLVulnerabilityKind kind | + exists(XML::XMLParsing parsing, XML::XMLVulnerabilityKind kind | (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and parsing.vulnerableTo(kind) and this = parsing.getAnInput() diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll index b2992dd335f..c118e1b2ff9 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll @@ -6,7 +6,8 @@ private import python private import semmle.python.dataflow.new.DataFlow -private import experimental.semmle.python.Concepts +private import semmle.python.Concepts +import experimental.semmle.python.frameworks.Xml // needed until modeling have been promoted private import semmle.python.dataflow.new.RemoteFlowSources /** @@ -40,7 +41,7 @@ module Xxe { */ class XmlParsingWithExternalEntityResolution extends Sink { XmlParsingWithExternalEntityResolution() { - exists(ExperimentalXML::XMLParsing parsing, ExperimentalXML::XMLVulnerabilityKind kind | + exists(XML::XMLParsing parsing, XML::XMLVulnerabilityKind kind | kind.isXxe() and parsing.vulnerableTo(kind) and this = parsing.getAnInput() diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql b/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql index 81bc391d0e5..679dbc3456c 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql +++ b/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql @@ -1,5 +1,5 @@ import python -import experimental.semmle.python.Concepts +import semmle.python.Concepts import experimental.semmle.python.frameworks.Xml import semmle.python.dataflow.new.DataFlow import TestUtilities.InlineExpectationsTest From e45288e812a0cd0f87cb909768b60847ec5aa997 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 29 Mar 2022 15:51:27 +0200 Subject: [PATCH 054/171] Python: => `XMLParsingVulnerabilityKind` Since there are other XML vulnerabilities that are not about parsing, this is more correct. --- python/ql/lib/semmle/python/Concepts.qll | 8 +++---- .../Security/CWE-611/SimpleXmlRpcServer.ql | 2 +- .../semmle/python/frameworks/Xml.qll | 24 +++++++++---------- .../dataflow/XmlBombCustomizations.qll | 2 +- .../security/dataflow/XxeCustomizations.qll | 2 +- .../XML/ExperimentalXmlConceptsTests.ql | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 3d83ec100a5..c430594d05b 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -556,8 +556,8 @@ module XML { * * See overview of kinds at https://pypi.org/project/defusedxml/#python-xml-libraries */ - class XMLVulnerabilityKind extends string { - XMLVulnerabilityKind() { + class XMLParsingVulnerabilityKind extends string { + XMLParsingVulnerabilityKind() { this in ["Billion Laughs", "Quadratic Blowup", "XXE", "DTD retrieval"] } @@ -589,7 +589,7 @@ module XML { /** * Holds if this XML parsing is vulnerable to `kind`. */ - predicate vulnerableTo(XMLVulnerabilityKind kind) { super.vulnerableTo(kind) } + predicate vulnerableTo(XMLParsingVulnerabilityKind kind) { super.vulnerableTo(kind) } } /** Provides classes for modeling XML parsing APIs. */ @@ -609,7 +609,7 @@ module XML { /** * Holds if this XML parsing is vulnerable to `kind`. */ - abstract predicate vulnerableTo(XMLVulnerabilityKind kind); + abstract predicate vulnerableTo(XMLParsingVulnerabilityKind kind); } } } diff --git a/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql b/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql index cda0633690c..3d2a736ed49 100644 --- a/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql +++ b/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql @@ -17,7 +17,7 @@ from DataFlow::CallCfgNode call, string kinds where call = API::moduleImport("xmlrpc").getMember("server").getMember("SimpleXMLRPCServer").getACall() and kinds = - strictconcat(ExperimentalXML::XMLVulnerabilityKind kind | + strictconcat(ExperimentalXML::XMLParsingVulnerabilityKind kind | kind.isBillionLaughs() or kind.isQuadraticBlowup() | kind, ", " diff --git a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll index 87aa236804d..4987e24bce4 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll @@ -66,7 +66,7 @@ private module XmlEtree { override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } - override predicate vulnerableTo(XML::XMLVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { kind.isBillionLaughs() or kind.isQuadraticBlowup() } } @@ -103,7 +103,7 @@ private module XmlEtree { ] } - override predicate vulnerableTo(XML::XMLVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { // note: it does not matter what `xml.etree` parser you are using, you cannot // change the security features anyway :| kind.isBillionLaughs() or kind.isQuadraticBlowup() @@ -218,7 +218,7 @@ private module SaxBasedParsing { override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("source")] } - override predicate vulnerableTo(XML::XMLVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { // always vuln to these (kind.isBillionLaughs() or kind.isQuadraticBlowup()) or @@ -251,7 +251,7 @@ private module SaxBasedParsing { ] } - override predicate vulnerableTo(XML::XMLVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { // always vuln to these (kind.isBillionLaughs() or kind.isQuadraticBlowup()) or @@ -290,7 +290,7 @@ private module SaxBasedParsing { DataFlow::Node getParserArg() { result in [this.getArg(1), this.getArgByName("parser")] } - override predicate vulnerableTo(XML::XMLVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { this.getParserArg() = saxParserWithFeatureExternalGesTurnedOn() and (kind.isXxe() or kind.isDtdRetrieval()) or @@ -317,7 +317,7 @@ private module Lxml { */ abstract class InstanceSource extends DataFlow::LocalSourceNode { /** Holds if this instance is vulnerable to `kind`. */ - abstract predicate vulnerableTo(XML::XMLVulnerabilityKind kind); + abstract predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind); } /** @@ -331,7 +331,7 @@ private module Lxml { } // NOTE: it's not possible to change settings of a parser after constructing it - override predicate vulnerableTo(XML::XMLVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { kind.isXxe() and ( // resolve_entities has default True @@ -361,7 +361,7 @@ private module Lxml { API::moduleImport("lxml").getMember("etree").getMember("get_default_parser").getACall() } - override predicate vulnerableTo(XML::XMLVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { // as highlighted by // https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.XMLParser // by default XXE is allow. so as long as the default parser has not been @@ -385,7 +385,7 @@ private module Lxml { } /** Gets a reference to an `lxml.etree` parser instance, that is vulnerable to `kind`. */ - DataFlow::Node instanceVulnerableTo(XML::XMLVulnerabilityKind kind) { + DataFlow::Node instanceVulnerableTo(XML::XMLParsingVulnerabilityKind kind) { exists(InstanceSource origin | result = instance(origin) and origin.vulnerableTo(kind)) } @@ -397,7 +397,7 @@ private module Lxml { override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } - override predicate vulnerableTo(XML::XMLVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { this.calls(instanceVulnerableTo(kind), "feed") } } @@ -436,7 +436,7 @@ private module Lxml { DataFlow::Node getParserArg() { result in [this.getArg(1), this.getArgByName("parser")] } - override predicate vulnerableTo(XML::XMLVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { this.getParserArg() = XMLParser::instanceVulnerableTo(kind) or kind.isXxe() and @@ -456,7 +456,7 @@ private module Xmltodict { result in [this.getArg(0), this.getArgByName("xml_input")] } - override predicate vulnerableTo(XML::XMLVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and this.getArgByName("disable_entities").getALocalSource().asExpr() = any(False f) } diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll index a4cbfe61821..c5e69c1e0e3 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll @@ -41,7 +41,7 @@ module XmlBomb { */ class XmlParsingWithEntityResolution extends Sink { XmlParsingWithEntityResolution() { - exists(XML::XMLParsing parsing, XML::XMLVulnerabilityKind kind | + exists(XML::XMLParsing parsing, XML::XMLParsingVulnerabilityKind kind | (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and parsing.vulnerableTo(kind) and this = parsing.getAnInput() diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll index c118e1b2ff9..27d011625a6 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll @@ -41,7 +41,7 @@ module Xxe { */ class XmlParsingWithExternalEntityResolution extends Sink { XmlParsingWithExternalEntityResolution() { - exists(XML::XMLParsing parsing, XML::XMLVulnerabilityKind kind | + exists(XML::XMLParsing parsing, XML::XMLParsingVulnerabilityKind kind | kind.isXxe() and parsing.vulnerableTo(kind) and this = parsing.getAnInput() diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql b/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql index 679dbc3456c..98237b447ea 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql +++ b/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql @@ -21,7 +21,7 @@ class XmlParsingTest extends InlineExpectationsTest { tag = "input" ) or - exists(XML::XMLVulnerabilityKind kind | + exists(XML::XMLParsingVulnerabilityKind kind | parsing.vulnerableTo(kind) and location = parsing.getLocation() and element = parsing.toString() and From 35ccba2ec10b2610969ac790d8ca8fa76a282ad9 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 29 Mar 2022 15:57:00 +0200 Subject: [PATCH 055/171] Python: Promote `XMLParsing` concept test --- ...tsTests.expected => ConceptsTest.expected} | 0 .../frameworks/XML/ConceptsTest.ql | 3 ++ .../XML/ExperimentalXmlConceptsTests.ql | 33 --------------- .../frameworks/XML/lxml_etree.py | 40 +++++++++---------- .../library-tests/frameworks/XML/xml_dom.py | 24 +++++------ .../library-tests/frameworks/XML/xml_etree.py | 34 ++++++++-------- .../library-tests/frameworks/XML/xml_sax.py | 26 ++++++------ .../library-tests/frameworks/XML/xmltodict.py | 6 +-- .../test/experimental/meta/ConceptsTest.qll | 27 +++++++++++++ 9 files changed, 95 insertions(+), 98 deletions(-) rename python/ql/test/experimental/library-tests/frameworks/XML/{ExperimentalXmlConceptsTests.expected => ConceptsTest.expected} (100%) create mode 100644 python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.ql delete mode 100644 python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.expected b/python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.expected rename to python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.ql b/python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.ql new file mode 100644 index 00000000000..95728bd6dc8 --- /dev/null +++ b/python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.ql @@ -0,0 +1,3 @@ +import python +import experimental.meta.ConceptsTest +import experimental.semmle.python.frameworks.Xml // needed until modeling have been promoted diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql b/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql deleted file mode 100644 index 98237b447ea..00000000000 --- a/python/ql/test/experimental/library-tests/frameworks/XML/ExperimentalXmlConceptsTests.ql +++ /dev/null @@ -1,33 +0,0 @@ -import python -import semmle.python.Concepts -import experimental.semmle.python.frameworks.Xml -import semmle.python.dataflow.new.DataFlow -import TestUtilities.InlineExpectationsTest -private import semmle.python.dataflow.new.internal.PrintNode - -class XmlParsingTest extends InlineExpectationsTest { - XmlParsingTest() { this = "XmlParsingTest" } - - override string getARelevantTag() { result in ["input", "vuln"] } - - override predicate hasActualResult(Location location, string element, string tag, string value) { - exists(location.getFile().getRelativePath()) and - exists(XML::XMLParsing parsing | - exists(DataFlow::Node input | - input = parsing.getAnInput() and - location = input.getLocation() and - element = input.toString() and - value = prettyNodeForInlineTest(input) and - tag = "input" - ) - or - exists(XML::XMLParsingVulnerabilityKind kind | - parsing.vulnerableTo(kind) and - location = parsing.getLocation() and - element = parsing.toString() and - value = "'" + kind + "'" and - tag = "vuln" - ) - ) - } -} diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/lxml_etree.py b/python/ql/test/experimental/library-tests/frameworks/XML/lxml_etree.py index 22930a58af3..ee8f3fc69c1 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/lxml_etree.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/lxml_etree.py @@ -4,51 +4,51 @@ import lxml.etree x = "some xml" # different parsing methods -lxml.etree.fromstring(x) # $ input=x vuln='XXE' -lxml.etree.fromstring(text=x) # $ input=x vuln='XXE' +lxml.etree.fromstring(x) # $ xmlInput=x xmlVuln='XXE' +lxml.etree.fromstring(text=x) # $ xmlInput=x xmlVuln='XXE' -lxml.etree.fromstringlist([x]) # $ input=List vuln='XXE' -lxml.etree.fromstringlist(strings=[x]) # $ input=List vuln='XXE' +lxml.etree.fromstringlist([x]) # $ xmlInput=List xmlVuln='XXE' +lxml.etree.fromstringlist(strings=[x]) # $ xmlInput=List xmlVuln='XXE' -lxml.etree.XML(x) # $ input=x vuln='XXE' -lxml.etree.XML(text=x) # $ input=x vuln='XXE' +lxml.etree.XML(x) # $ xmlInput=x xmlVuln='XXE' +lxml.etree.XML(text=x) # $ xmlInput=x xmlVuln='XXE' -lxml.etree.parse(StringIO(x)) # $ input=StringIO(..) vuln='XXE' -lxml.etree.parse(source=StringIO(x)) # $ input=StringIO(..) vuln='XXE' +lxml.etree.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='XXE' +lxml.etree.parse(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='XXE' -lxml.etree.parseid(StringIO(x)) # $ input=StringIO(..) vuln='XXE' -lxml.etree.parseid(source=StringIO(x)) # $ input=StringIO(..) vuln='XXE' +lxml.etree.parseid(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='XXE' +lxml.etree.parseid(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='XXE' # With default parsers (nothing changed) parser = lxml.etree.XMLParser() -lxml.etree.fromstring(x, parser=parser) # $ input=x vuln='XXE' +lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='XXE' parser = lxml.etree.get_default_parser() -lxml.etree.fromstring(x, parser=parser) # $ input=x vuln='XXE' +lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='XXE' # manual use of feed method parser = lxml.etree.XMLParser() -parser.feed(x) # $ input=x vuln='XXE' -parser.feed(data=x) # $ input=x vuln='XXE' +parser.feed(x) # $ xmlInput=x xmlVuln='XXE' +parser.feed(data=x) # $ xmlInput=x xmlVuln='XXE' parser.close() # XXE-safe parser = lxml.etree.XMLParser(resolve_entities=False) -lxml.etree.fromstring(x, parser) # $ input=x -lxml.etree.fromstring(x, parser=parser) # $ input=x +lxml.etree.fromstring(x, parser) # $ xmlInput=x +lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x # XXE-vuln parser = lxml.etree.XMLParser(resolve_entities=True) -lxml.etree.fromstring(x, parser=parser) # $ input=x vuln='XXE' +lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='XXE' # Billion laughs vuln (also XXE) parser = lxml.etree.XMLParser(huge_tree=True) -lxml.etree.fromstring(x, parser=parser) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' vuln='XXE' +lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' xmlVuln='XXE' # Safe for both Billion laughs and XXE parser = lxml.etree.XMLParser(resolve_entities=False, huge_tree=True) -lxml.etree.fromstring(x, parser=parser) # $ input=x +lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x # DTD retrival vuln (also XXE) parser = lxml.etree.XMLParser(load_dtd=True, no_network=False) -lxml.etree.fromstring(x, parser=parser) # $ input=x vuln='DTD retrieval' vuln='XXE' +lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='DTD retrieval' xmlVuln='XXE' diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xml_dom.py b/python/ql/test/experimental/library-tests/frameworks/XML/xml_dom.py index 7dce29fc7b9..b86770b8d6c 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/xml_dom.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/xml_dom.py @@ -6,26 +6,26 @@ import xml.sax x = "some xml" # minidom -xml.dom.minidom.parse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.dom.minidom.parse(file=StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.dom.minidom.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.dom.minidom.parse(file=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.dom.minidom.parseString(x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.dom.minidom.parseString(string=x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.dom.minidom.parseString(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.dom.minidom.parseString(string=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' # pulldom -xml.dom.pulldom.parse(StringIO(x))['START_DOCUMENT'][1] # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.dom.pulldom.parse(stream_or_string=StringIO(x))['START_DOCUMENT'][1] # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.dom.pulldom.parse(StringIO(x))['START_DOCUMENT'][1] # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.dom.pulldom.parse(stream_or_string=StringIO(x))['START_DOCUMENT'][1] # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.dom.pulldom.parseString(x)['START_DOCUMENT'][1] # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.dom.pulldom.parseString(string=x)['START_DOCUMENT'][1] # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.dom.pulldom.parseString(x)['START_DOCUMENT'][1] # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.dom.pulldom.parseString(string=x)['START_DOCUMENT'][1] # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' # These are based on SAX parses, and you can specify your own, so you can expose yourself to XXE (yay/) parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) -xml.dom.minidom.parse(StringIO(x), parser) # $ input=StringIO(..) vuln='Billion Laughs' vuln='DTD retrieval' vuln='Quadratic Blowup' vuln='XXE' -xml.dom.minidom.parse(StringIO(x), parser=parser) # $ input=StringIO(..) vuln='Billion Laughs' vuln='DTD retrieval' vuln='Quadratic Blowup' vuln='XXE' +xml.dom.minidom.parse(StringIO(x), parser) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' +xml.dom.minidom.parse(StringIO(x), parser=parser) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' -xml.dom.pulldom.parse(StringIO(x), parser) # $ input=StringIO(..) vuln='Billion Laughs' vuln='DTD retrieval' vuln='Quadratic Blowup' vuln='XXE' -xml.dom.pulldom.parse(StringIO(x), parser=parser) # $ input=StringIO(..) vuln='Billion Laughs' vuln='DTD retrieval' vuln='Quadratic Blowup' vuln='XXE' +xml.dom.pulldom.parse(StringIO(x), parser) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' +xml.dom.pulldom.parse(StringIO(x), parser=parser) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xml_etree.py b/python/ql/test/experimental/library-tests/frameworks/XML/xml_etree.py index df126e458e2..c5d141a3715 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/xml_etree.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/xml_etree.py @@ -4,39 +4,39 @@ import xml.etree.ElementTree x = "some xml" # Parsing in different ways -xml.etree.ElementTree.fromstring(x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.etree.ElementTree.fromstring(text=x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.etree.ElementTree.fromstring(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.fromstring(text=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.etree.ElementTree.fromstringlist([x]) # $ input=List vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.etree.ElementTree.fromstringlist(sequence=[x]) # $ input=List vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.etree.ElementTree.fromstringlist([x]) # $ xmlInput=List xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.fromstringlist(sequence=[x]) # $ xmlInput=List xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.etree.ElementTree.XML(x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.etree.ElementTree.XML(text=x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.etree.ElementTree.XML(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.XML(text=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.etree.ElementTree.XMLID(x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.etree.ElementTree.XMLID(text=x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.etree.ElementTree.XMLID(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.XMLID(text=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.etree.ElementTree.parse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.etree.ElementTree.parse(source=StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.etree.ElementTree.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.parse(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.etree.ElementTree.iterparse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.etree.ElementTree.iterparse(source=StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.etree.ElementTree.iterparse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.iterparse(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' # With parsers (no options available to disable/enable security features) parser = xml.etree.ElementTree.XMLParser() -xml.etree.ElementTree.fromstring(x, parser=parser) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.etree.ElementTree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' # manual use of feed method parser = xml.etree.ElementTree.XMLParser() -parser.feed(x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' -parser.feed(data=x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' +parser.feed(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.feed(data=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' parser.close() # manual use of feed method on XMLPullParser parser = xml.etree.ElementTree.XMLPullParser() -parser.feed(x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' -parser.feed(data=x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' +parser.feed(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.feed(data=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' parser.close() # note: it's technically possible to use the thing wrapper func `fromstring` with an diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xml_sax.py b/python/ql/test/experimental/library-tests/frameworks/XML/xml_sax.py index 158e62ffae6..c0e5923c5c0 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/xml_sax.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/xml_sax.py @@ -10,41 +10,41 @@ class MainHandler(xml.sax.ContentHandler): def characters(self, data): self._result.append(data) -xml.sax.parse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.sax.parse(source=StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.sax.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.sax.parse(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.sax.parseString(x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' -xml.sax.parseString(string=x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' +xml.sax.parseString(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.sax.parseString(string=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' parser = xml.sax.make_parser() -parser.parse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' -parser.parse(source=StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' +parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.parse(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' # You can make it vuln to both XXE and DTD retrieval by setting this flag # see https://docs.python.org/3/library/xml.sax.handler.html#xml.sax.handler.feature_external_ges parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) -parser.parse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='DTD retrieval' vuln='Quadratic Blowup' vuln='XXE' +parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, False) -parser.parse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' +parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' # Forward Type Tracking test def func(cond): parser = xml.sax.make_parser() if cond: parser.setFeature(xml.sax.handler.feature_external_ges, True) - parser.parse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='DTD retrieval' vuln='Quadratic Blowup' vuln='XXE' + parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' else: - parser.parse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' + parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' # make it vuln, then making it safe # a bit of an edge-case, but is nice to be able to handle. parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) parser.setFeature(xml.sax.handler.feature_external_ges, False) -parser.parse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='Quadratic Blowup' +parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' def check_conditional_assignment(cond): parser = xml.sax.make_parser() @@ -52,7 +52,7 @@ def check_conditional_assignment(cond): parser.setFeature(xml.sax.handler.feature_external_ges, True) else: parser.setFeature(xml.sax.handler.feature_external_ges, False) - parser.parse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='DTD retrieval' vuln='Quadratic Blowup' vuln='XXE' + parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' def check_conditional_assignment2(cond): parser = xml.sax.make_parser() @@ -61,4 +61,4 @@ def check_conditional_assignment2(cond): else: flag_value = False parser.setFeature(xml.sax.handler.feature_external_ges, flag_value) - parser.parse(StringIO(x)) # $ input=StringIO(..) vuln='Billion Laughs' vuln='DTD retrieval' vuln='Quadratic Blowup' vuln='XXE' + parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xmltodict.py b/python/ql/test/experimental/library-tests/frameworks/XML/xmltodict.py index 473e51c9fe6..27d04862f83 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/xmltodict.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/xmltodict.py @@ -2,7 +2,7 @@ import xmltodict x = "some xml" -xmltodict.parse(x) # $ input=x -xmltodict.parse(xml_input=x) # $ input=x +xmltodict.parse(x) # $ xmlInput=x +xmltodict.parse(xml_input=x) # $ xmlInput=x -xmltodict.parse(x, disable_entities=False) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup' +xmltodict.parse(x, disable_entities=False) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 8f9435f633f..e9f71356963 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -539,3 +539,30 @@ class HttpClientRequestTest extends InlineExpectationsTest { ) } } + +class XmlParsingTest extends InlineExpectationsTest { + XmlParsingTest() { this = "XmlParsingTest" } + + override string getARelevantTag() { result in ["xmlInput", "xmlVuln"] } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(XML::XMLParsing parsing | + exists(DataFlow::Node input | + input = parsing.getAnInput() and + location = input.getLocation() and + element = input.toString() and + value = prettyNodeForInlineTest(input) and + tag = "xmlInput" + ) + or + exists(XML::XMLParsingVulnerabilityKind kind | + parsing.vulnerableTo(kind) and + location = parsing.getLocation() and + element = parsing.toString() and + value = "'" + kind + "'" and + tag = "xmlVuln" + ) + ) + } +} From 1ea4bcc59f4ccbfe02e454ae3223a8fa34ac33e3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 29 Mar 2022 16:48:30 +0200 Subject: [PATCH 056/171] Python: Make `XMLParsing` a `Decoding` subclass --- python/ql/lib/semmle/python/Concepts.qll | 16 ++---- .../semmle/python/frameworks/Xml.qll | 52 +++++++++++++++++++ .../frameworks/XML/lxml_etree.py | 42 +++++++-------- .../library-tests/frameworks/XML/xml_dom.py | 24 ++++----- .../library-tests/frameworks/XML/xml_etree.py | 38 +++++++------- .../library-tests/frameworks/XML/xml_sax.py | 26 +++++----- .../library-tests/frameworks/XML/xmltodict.py | 6 +-- .../test/experimental/meta/ConceptsTest.qll | 8 --- 8 files changed, 124 insertions(+), 88 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index c430594d05b..b553c8d927d 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -580,12 +580,7 @@ module XML { * Extend this class to model new APIs. If you want to refine existing API models, * extend `XMLParsing` instead. */ - class XMLParsing extends DataFlow::Node instanceof XMLParsing::Range { - /** - * Gets the argument containing the content to parse. - */ - DataFlow::Node getAnInput() { result = super.getAnInput() } - + class XMLParsing extends Decoding instanceof XMLParsing::Range { /** * Holds if this XML parsing is vulnerable to `kind`. */ @@ -600,16 +595,13 @@ module XML { * Extend this class to model new APIs. If you want to refine existing API models, * extend `XMLParsing` instead. */ - abstract class Range extends DataFlow::Node { - /** - * Gets the argument containing the content to parse. - */ - abstract DataFlow::Node getAnInput(); - + abstract class Range extends Decoding::Range { /** * Holds if this XML parsing is vulnerable to `kind`. */ abstract predicate vulnerableTo(XMLParsingVulnerabilityKind kind); + + override string getFormat() { result = "XML" } } } } diff --git a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll index 4987e24bce4..c072295c461 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll @@ -69,6 +69,15 @@ private module XmlEtree { override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { kind.isBillionLaughs() or kind.isQuadraticBlowup() } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { + exists(DataFlow::Node objRef | + DataFlow::localFlow(this.getObject(), objRef) and + result.(DataFlow::MethodCallNode).calls(objRef, "close") + ) + } } } @@ -108,6 +117,10 @@ private module XmlEtree { // change the security features anyway :| kind.isBillionLaughs() or kind.isQuadraticBlowup() } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { result = this } } } @@ -226,6 +239,15 @@ private module SaxBasedParsing { this.getObject() = saxParserWithFeatureExternalGesTurnedOn() and (kind.isXxe() or kind.isDtdRetrieval()) } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { + // note: the output of parsing with SAX is that the content handler gets the + // data... but we don't currently model this (it's not trivial to do, and won't + // really give us any value, at least not as of right now). + none() + } } /** @@ -259,6 +281,15 @@ private module SaxBasedParsing { this.getObject() = saxParserWithFeatureExternalGesTurnedOn() and (kind.isXxe() or kind.isDtdRetrieval()) } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { + // note: the output of parsing with SAX is that the content handler gets the + // data... but we don't currently model this (it's not trivial to do, and won't + // really give us any value, at least not as of right now). + none() + } } /** @@ -296,6 +327,10 @@ private module SaxBasedParsing { or (kind.isBillionLaughs() or kind.isQuadraticBlowup()) } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { result = this } } } @@ -400,6 +435,15 @@ private module Lxml { override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { this.calls(instanceVulnerableTo(kind), "feed") } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { + exists(DataFlow::Node objRef | + DataFlow::localFlow(this.getObject(), objRef) and + result.(DataFlow::MethodCallNode).calls(objRef, "close") + ) + } } } @@ -442,6 +486,10 @@ private module Lxml { kind.isXxe() and not exists(this.getParserArg()) } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { result = this } } } @@ -460,5 +508,9 @@ private module Xmltodict { (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and this.getArgByName("disable_entities").getALocalSource().asExpr() = any(False f) } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { result = this } } } diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/lxml_etree.py b/python/ql/test/experimental/library-tests/frameworks/XML/lxml_etree.py index ee8f3fc69c1..f1dbd5390ad 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/lxml_etree.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/lxml_etree.py @@ -4,51 +4,51 @@ import lxml.etree x = "some xml" # different parsing methods -lxml.etree.fromstring(x) # $ xmlInput=x xmlVuln='XXE' -lxml.etree.fromstring(text=x) # $ xmlInput=x xmlVuln='XXE' +lxml.etree.fromstring(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.fromstring(..) +lxml.etree.fromstring(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.fromstring(..) -lxml.etree.fromstringlist([x]) # $ xmlInput=List xmlVuln='XXE' -lxml.etree.fromstringlist(strings=[x]) # $ xmlInput=List xmlVuln='XXE' +lxml.etree.fromstringlist([x]) # $ decodeFormat=XML decodeInput=List xmlVuln='XXE' decodeOutput=lxml.etree.fromstringlist(..) +lxml.etree.fromstringlist(strings=[x]) # $ decodeFormat=XML decodeInput=List xmlVuln='XXE' decodeOutput=lxml.etree.fromstringlist(..) -lxml.etree.XML(x) # $ xmlInput=x xmlVuln='XXE' -lxml.etree.XML(text=x) # $ xmlInput=x xmlVuln='XXE' +lxml.etree.XML(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.XML(..) +lxml.etree.XML(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.XML(..) -lxml.etree.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='XXE' -lxml.etree.parse(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='XXE' +lxml.etree.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) +lxml.etree.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) -lxml.etree.parseid(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='XXE' -lxml.etree.parseid(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='XXE' +lxml.etree.parseid(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XXE' decodeOutput=lxml.etree.parseid(..) +lxml.etree.parseid(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XXE' decodeOutput=lxml.etree.parseid(..) # With default parsers (nothing changed) parser = lxml.etree.XMLParser() -lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='XXE' +lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.fromstring(..) parser = lxml.etree.get_default_parser() -lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='XXE' +lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.fromstring(..) # manual use of feed method parser = lxml.etree.XMLParser() -parser.feed(x) # $ xmlInput=x xmlVuln='XXE' -parser.feed(data=x) # $ xmlInput=x xmlVuln='XXE' -parser.close() +parser.feed(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' +parser.feed(data=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' +parser.close() # $ decodeOutput=parser.close() # XXE-safe parser = lxml.etree.XMLParser(resolve_entities=False) -lxml.etree.fromstring(x, parser) # $ xmlInput=x -lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x +lxml.etree.fromstring(x, parser) # $ decodeFormat=XML decodeInput=x decodeOutput=lxml.etree.fromstring(..) +lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x decodeOutput=lxml.etree.fromstring(..) # XXE-vuln parser = lxml.etree.XMLParser(resolve_entities=True) -lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='XXE' +lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.fromstring(..) # Billion laughs vuln (also XXE) parser = lxml.etree.XMLParser(huge_tree=True) -lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' xmlVuln='XXE' +lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=lxml.etree.fromstring(..) # Safe for both Billion laughs and XXE parser = lxml.etree.XMLParser(resolve_entities=False, huge_tree=True) -lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x +lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x decodeOutput=lxml.etree.fromstring(..) # DTD retrival vuln (also XXE) parser = lxml.etree.XMLParser(load_dtd=True, no_network=False) -lxml.etree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='DTD retrieval' xmlVuln='XXE' +lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVuln='DTD retrieval' xmlVuln='XXE' decodeOutput=lxml.etree.fromstring(..) diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xml_dom.py b/python/ql/test/experimental/library-tests/frameworks/XML/xml_dom.py index b86770b8d6c..c6152c75807 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/xml_dom.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/xml_dom.py @@ -6,26 +6,26 @@ import xml.sax x = "some xml" # minidom -xml.dom.minidom.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.dom.minidom.parse(file=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.dom.minidom.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parse(..) +xml.dom.minidom.parse(file=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parse(..) -xml.dom.minidom.parseString(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.dom.minidom.parseString(string=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.dom.minidom.parseString(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parseString(..) +xml.dom.minidom.parseString(string=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parseString(..) # pulldom -xml.dom.pulldom.parse(StringIO(x))['START_DOCUMENT'][1] # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.dom.pulldom.parse(stream_or_string=StringIO(x))['START_DOCUMENT'][1] # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.dom.pulldom.parse(StringIO(x))['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parse(..) +xml.dom.pulldom.parse(stream_or_string=StringIO(x))['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parse(..) -xml.dom.pulldom.parseString(x)['START_DOCUMENT'][1] # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.dom.pulldom.parseString(string=x)['START_DOCUMENT'][1] # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.dom.pulldom.parseString(x)['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parseString(..) +xml.dom.pulldom.parseString(string=x)['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parseString(..) # These are based on SAX parses, and you can specify your own, so you can expose yourself to XXE (yay/) parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) -xml.dom.minidom.parse(StringIO(x), parser) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' -xml.dom.minidom.parse(StringIO(x), parser=parser) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' +xml.dom.minidom.parse(StringIO(x), parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.minidom.parse(..) +xml.dom.minidom.parse(StringIO(x), parser=parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.minidom.parse(..) -xml.dom.pulldom.parse(StringIO(x), parser) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' -xml.dom.pulldom.parse(StringIO(x), parser=parser) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' +xml.dom.pulldom.parse(StringIO(x), parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.pulldom.parse(..) +xml.dom.pulldom.parse(StringIO(x), parser=parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.pulldom.parse(..) diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xml_etree.py b/python/ql/test/experimental/library-tests/frameworks/XML/xml_etree.py index c5d141a3715..0ed750ba8c7 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/xml_etree.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/xml_etree.py @@ -4,40 +4,40 @@ import xml.etree.ElementTree x = "some xml" # Parsing in different ways -xml.etree.ElementTree.fromstring(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.etree.ElementTree.fromstring(text=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.fromstring(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.fromstring(..) +xml.etree.ElementTree.fromstring(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.fromstring(..) -xml.etree.ElementTree.fromstringlist([x]) # $ xmlInput=List xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.etree.ElementTree.fromstringlist(sequence=[x]) # $ xmlInput=List xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.fromstringlist([x]) # $ decodeFormat=XML decodeInput=List xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.fromstringlist(..) +xml.etree.ElementTree.fromstringlist(sequence=[x]) # $ decodeFormat=XML decodeInput=List xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.fromstringlist(..) -xml.etree.ElementTree.XML(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.etree.ElementTree.XML(text=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.XML(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.XML(..) +xml.etree.ElementTree.XML(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.XML(..) -xml.etree.ElementTree.XMLID(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.etree.ElementTree.XMLID(text=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.XMLID(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.XMLID(..) +xml.etree.ElementTree.XMLID(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.XMLID(..) -xml.etree.ElementTree.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.etree.ElementTree.parse(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.parse(..) +xml.etree.ElementTree.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.parse(..) -xml.etree.ElementTree.iterparse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.etree.ElementTree.iterparse(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.iterparse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.iterparse(..) +xml.etree.ElementTree.iterparse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.iterparse(..) # With parsers (no options available to disable/enable security features) parser = xml.etree.ElementTree.XMLParser() -xml.etree.ElementTree.fromstring(x, parser=parser) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.etree.ElementTree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.fromstring(..) # manual use of feed method parser = xml.etree.ElementTree.XMLParser() -parser.feed(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -parser.feed(data=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -parser.close() +parser.feed(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.feed(data=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.close() # $ decodeOutput=parser.close() # manual use of feed method on XMLPullParser parser = xml.etree.ElementTree.XMLPullParser() -parser.feed(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -parser.feed(data=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -parser.close() +parser.feed(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.feed(data=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.close() # $ decodeOutput=parser.close() # note: it's technically possible to use the thing wrapper func `fromstring` with an # `lxml` parser, and thereby change what vulnerabilities you are exposed to.. but it diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xml_sax.py b/python/ql/test/experimental/library-tests/frameworks/XML/xml_sax.py index c0e5923c5c0..8dbe9d4ae99 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/xml_sax.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/xml_sax.py @@ -10,41 +10,41 @@ class MainHandler(xml.sax.ContentHandler): def characters(self, data): self._result.append(data) -xml.sax.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.sax.parse(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.sax.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.sax.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.sax.parseString(x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.sax.parseString(string=x) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.sax.parseString(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.sax.parseString(string=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' parser = xml.sax.make_parser() -parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -parser.parse(source=StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' # You can make it vuln to both XXE and DTD retrieval by setting this flag # see https://docs.python.org/3/library/xml.sax.handler.html#xml.sax.handler.feature_external_ges parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) -parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, False) -parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' # Forward Type Tracking test def func(cond): parser = xml.sax.make_parser() if cond: parser.setFeature(xml.sax.handler.feature_external_ges, True) - parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' else: - parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' # make it vuln, then making it safe # a bit of an edge-case, but is nice to be able to handle. parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) parser.setFeature(xml.sax.handler.feature_external_ges, False) -parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' def check_conditional_assignment(cond): parser = xml.sax.make_parser() @@ -52,7 +52,7 @@ def check_conditional_assignment(cond): parser.setFeature(xml.sax.handler.feature_external_ges, True) else: parser.setFeature(xml.sax.handler.feature_external_ges, False) - parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' def check_conditional_assignment2(cond): parser = xml.sax.make_parser() @@ -61,4 +61,4 @@ def check_conditional_assignment2(cond): else: flag_value = False parser.setFeature(xml.sax.handler.feature_external_ges, flag_value) - parser.parse(StringIO(x)) # $ xmlInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xmltodict.py b/python/ql/test/experimental/library-tests/frameworks/XML/xmltodict.py index 27d04862f83..01dc2f3c484 100644 --- a/python/ql/test/experimental/library-tests/frameworks/XML/xmltodict.py +++ b/python/ql/test/experimental/library-tests/frameworks/XML/xmltodict.py @@ -2,7 +2,7 @@ import xmltodict x = "some xml" -xmltodict.parse(x) # $ xmlInput=x -xmltodict.parse(xml_input=x) # $ xmlInput=x +xmltodict.parse(x) # $ decodeFormat=XML decodeInput=x decodeOutput=xmltodict.parse(..) +xmltodict.parse(xml_input=x) # $ decodeFormat=XML decodeInput=x decodeOutput=xmltodict.parse(..) -xmltodict.parse(x, disable_entities=False) # $ xmlInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xmltodict.parse(x, disable_entities=False) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xmltodict.parse(..) diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index e9f71356963..24cbbab2d44 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -548,14 +548,6 @@ class XmlParsingTest extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(XML::XMLParsing parsing | - exists(DataFlow::Node input | - input = parsing.getAnInput() and - location = input.getLocation() and - element = input.toString() and - value = prettyNodeForInlineTest(input) and - tag = "xmlInput" - ) - or exists(XML::XMLParsingVulnerabilityKind kind | parsing.vulnerableTo(kind) and location = parsing.getLocation() and From c4473c5f6506e6dcb8e6736f7d3ddd0acea022d4 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 10:08:02 +0200 Subject: [PATCH 057/171] Python: Rename lxml XPath tests --- .../ql/test/library-tests/frameworks/lxml/{test.py => xpath.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename python/ql/test/library-tests/frameworks/lxml/{test.py => xpath.py} (100%) diff --git a/python/ql/test/library-tests/frameworks/lxml/test.py b/python/ql/test/library-tests/frameworks/lxml/xpath.py similarity index 100% rename from python/ql/test/library-tests/frameworks/lxml/test.py rename to python/ql/test/library-tests/frameworks/lxml/xpath.py From 3040adfd9bdc26a0c54ef04453a1c8b2420bb4c5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 10:08:26 +0200 Subject: [PATCH 058/171] Python: Handle `XMLParser().close()` for XPath --- .../ql/lib/semmle/python/frameworks/Lxml.qll | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index 9259668a5c8..ab29f33e7cf 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -57,13 +57,25 @@ private module Lxml { */ class XPathCall extends XML::XPathExecution::Range, DataFlow::CallCfgNode { XPathCall() { - this = - API::moduleImport("lxml") - .getMember("etree") - .getMember(["parse", "fromstring", "fromstringlist", "HTML", "XML"]) - .getReturn() - .getMember("xpath") - .getACall() + exists(API::Node parseResult | + parseResult = + API::moduleImport("lxml") + .getMember("etree") + .getMember(["parse", "fromstring", "fromstringlist", "HTML", "XML"]) + .getReturn() + or + // TODO: lxml.etree.parseid()[0] will contain the root element from parsing + // but we don't really have a way to model that nicely. + parseResult = + API::moduleImport("lxml") + .getMember("etree") + .getMember("XMLParser") + .getReturn() + .getMember("close") + .getReturn() + | + this = parseResult.getMember("xpath").getACall() + ) } override DataFlow::Node getXPath() { result in [this.getArg(0), this.getArgByName("_path")] } From 80b5cde3a2d3123029630450e41475f89253938c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 10:19:08 +0200 Subject: [PATCH 059/171] Python: Promote lxml parsing modeling --- .../ql/lib/semmle/python/frameworks/Lxml.qll | 163 ++++++++++++++++++ .../semmle/python/frameworks/Xml.qll | 159 ----------------- .../frameworks/lxml/parsing.py} | 0 .../library-tests/frameworks/lxml/xpath.py | 8 +- 4 files changed, 167 insertions(+), 163 deletions(-) rename python/ql/test/{experimental/library-tests/frameworks/XML/lxml_etree.py => library-tests/frameworks/lxml/parsing.py} (100%) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index ab29f33e7cf..de89345a7d6 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -19,6 +19,9 @@ private import semmle.python.ApiGraphs * - https://lxml.de/tutorial.html */ private module Lxml { + // --------------------------------------------------------------------------- + // XPath + // --------------------------------------------------------------------------- /** * A class constructor compiling an XPath expression. * @@ -97,4 +100,164 @@ private module Lxml { override string getName() { result = "lxml.etree" } } + + // --------------------------------------------------------------------------- + // Parsing + // --------------------------------------------------------------------------- + /** + * Provides models for `lxml.etree` parsers. + * + * See https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.XMLParser + */ + module XMLParser { + /** + * A source of instances of `lxml.etree` parsers, extend this class to model new instances. + * + * This can include instantiations of the class, return values from function + * calls, or a special parameter that will be set when functions are called by an external + * library. + * + * Use the predicate `XMLParser::instance()` to get references to instances of `lxml.etree` parsers. + */ + abstract class InstanceSource extends DataFlow::LocalSourceNode { + /** Holds if this instance is vulnerable to `kind`. */ + abstract predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind); + } + + /** + * A call to `lxml.etree.XMLParser`. + * + * See https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.XMLParser + */ + private class LXMLParser extends InstanceSource, DataFlow::CallCfgNode { + LXMLParser() { + this = API::moduleImport("lxml").getMember("etree").getMember("XMLParser").getACall() + } + + // NOTE: it's not possible to change settings of a parser after constructing it + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + kind.isXxe() and + ( + // resolve_entities has default True + not exists(this.getArgByName("resolve_entities")) + or + this.getArgByName("resolve_entities").getALocalSource().asExpr() = any(True t) + ) + or + (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and + this.getArgByName("huge_tree").getALocalSource().asExpr() = any(True t) and + not this.getArgByName("resolve_entities").getALocalSource().asExpr() = any(False t) + or + kind.isDtdRetrieval() and + this.getArgByName("load_dtd").getALocalSource().asExpr() = any(True t) and + this.getArgByName("no_network").getALocalSource().asExpr() = any(False t) + } + } + + /** + * A call to `lxml.etree.get_default_parser`. + * + * See https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.get_default_parser + */ + private class LXMLDefaultParser extends InstanceSource, DataFlow::CallCfgNode { + LXMLDefaultParser() { + this = + API::moduleImport("lxml").getMember("etree").getMember("get_default_parser").getACall() + } + + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + // as highlighted by + // https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.XMLParser + // by default XXE is allow. so as long as the default parser has not been + // overridden, the result is also vuln to XXE. + kind.isXxe() + // TODO: take into account that you can override the default parser with `lxml.etree.set_default_parser`. + } + } + + /** Gets a reference to an `lxml.etree` parsers instance, with origin in `origin` */ + private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t, InstanceSource origin) { + t.start() and + result = origin + or + exists(DataFlow::TypeTracker t2 | result = instance(t2, origin).track(t2, t)) + } + + /** Gets a reference to an `lxml.etree` parsers instance, with origin in `origin` */ + DataFlow::Node instance(InstanceSource origin) { + instance(DataFlow::TypeTracker::end(), origin).flowsTo(result) + } + + /** Gets a reference to an `lxml.etree` parser instance, that is vulnerable to `kind`. */ + DataFlow::Node instanceVulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + exists(InstanceSource origin | result = instance(origin) and origin.vulnerableTo(kind)) + } + + /** + * A call to the `feed` method of an `lxml` parser. + */ + private class LXMLParserFeedCall extends DataFlow::MethodCallNode, XML::XMLParsing::Range { + LXMLParserFeedCall() { this.calls(instance(_), "feed") } + + override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } + + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + this.calls(instanceVulnerableTo(kind), "feed") + } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { + exists(DataFlow::Node objRef | + DataFlow::localFlow(this.getObject(), objRef) and + result.(DataFlow::MethodCallNode).calls(objRef, "close") + ) + } + } + } + + /** + * A call to either of: + * - `lxml.etree.fromstring` + * - `lxml.etree.fromstringlist` + * - `lxml.etree.XML` + * - `lxml.etree.parse` + * - `lxml.etree.parseid` + * + * See https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.fromstring + */ + private class LXMLParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { + LXMLParsing() { + this = + API::moduleImport("lxml") + .getMember("etree") + .getMember(["fromstring", "fromstringlist", "XML", "parse", "parseid"]) + .getACall() + } + + override DataFlow::Node getAnInput() { + result in [ + this.getArg(0), + // fromstring / XML + this.getArgByName("text"), + // fromstringlist + this.getArgByName("strings"), + // parse / parseid + this.getArgByName("source"), + ] + } + + DataFlow::Node getParserArg() { result in [this.getArg(1), this.getArgByName("parser")] } + + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + this.getParserArg() = XMLParser::instanceVulnerableTo(kind) + or + kind.isXxe() and + not exists(this.getParserArg()) + } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { result = this } + } } diff --git a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll index c072295c461..b31151eed1a 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll @@ -334,165 +334,6 @@ private module SaxBasedParsing { } } -private module Lxml { - /** - * Provides models for `lxml.etree` parsers. - * - * See https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.XMLParser - */ - module XMLParser { - /** - * A source of instances of `lxml.etree` parsers, extend this class to model new instances. - * - * This can include instantiations of the class, return values from function - * calls, or a special parameter that will be set when functions are called by an external - * library. - * - * Use the predicate `XMLParser::instance()` to get references to instances of `lxml.etree` parsers. - */ - abstract class InstanceSource extends DataFlow::LocalSourceNode { - /** Holds if this instance is vulnerable to `kind`. */ - abstract predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind); - } - - /** - * A call to `lxml.etree.XMLParser`. - * - * See https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.XMLParser - */ - private class LXMLParser extends InstanceSource, DataFlow::CallCfgNode { - LXMLParser() { - this = API::moduleImport("lxml").getMember("etree").getMember("XMLParser").getACall() - } - - // NOTE: it's not possible to change settings of a parser after constructing it - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { - kind.isXxe() and - ( - // resolve_entities has default True - not exists(this.getArgByName("resolve_entities")) - or - this.getArgByName("resolve_entities").getALocalSource().asExpr() = any(True t) - ) - or - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and - this.getArgByName("huge_tree").getALocalSource().asExpr() = any(True t) and - not this.getArgByName("resolve_entities").getALocalSource().asExpr() = any(False t) - or - kind.isDtdRetrieval() and - this.getArgByName("load_dtd").getALocalSource().asExpr() = any(True t) and - this.getArgByName("no_network").getALocalSource().asExpr() = any(False t) - } - } - - /** - * A call to `lxml.etree.get_default_parser`. - * - * See https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.get_default_parser - */ - private class LXMLDefaultParser extends InstanceSource, DataFlow::CallCfgNode { - LXMLDefaultParser() { - this = - API::moduleImport("lxml").getMember("etree").getMember("get_default_parser").getACall() - } - - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { - // as highlighted by - // https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.XMLParser - // by default XXE is allow. so as long as the default parser has not been - // overridden, the result is also vuln to XXE. - kind.isXxe() - // TODO: take into account that you can override the default parser with `lxml.etree.set_default_parser`. - } - } - - /** Gets a reference to an `lxml.etree` parsers instance, with origin in `origin` */ - private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t, InstanceSource origin) { - t.start() and - result = origin - or - exists(DataFlow::TypeTracker t2 | result = instance(t2, origin).track(t2, t)) - } - - /** Gets a reference to an `lxml.etree` parsers instance, with origin in `origin` */ - DataFlow::Node instance(InstanceSource origin) { - instance(DataFlow::TypeTracker::end(), origin).flowsTo(result) - } - - /** Gets a reference to an `lxml.etree` parser instance, that is vulnerable to `kind`. */ - DataFlow::Node instanceVulnerableTo(XML::XMLParsingVulnerabilityKind kind) { - exists(InstanceSource origin | result = instance(origin) and origin.vulnerableTo(kind)) - } - - /** - * A call to the `feed` method of an `lxml` parser. - */ - private class LXMLParserFeedCall extends DataFlow::MethodCallNode, XML::XMLParsing::Range { - LXMLParserFeedCall() { this.calls(instance(_), "feed") } - - override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } - - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { - this.calls(instanceVulnerableTo(kind), "feed") - } - - override predicate mayExecuteInput() { none() } - - override DataFlow::Node getOutput() { - exists(DataFlow::Node objRef | - DataFlow::localFlow(this.getObject(), objRef) and - result.(DataFlow::MethodCallNode).calls(objRef, "close") - ) - } - } - } - - /** - * A call to either of: - * - `lxml.etree.fromstring` - * - `lxml.etree.fromstringlist` - * - `lxml.etree.XML` - * - `lxml.etree.parse` - * - `lxml.etree.parseid` - * - * See https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.fromstring - */ - private class LXMLParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { - LXMLParsing() { - this = - API::moduleImport("lxml") - .getMember("etree") - .getMember(["fromstring", "fromstringlist", "XML", "parse", "parseid"]) - .getACall() - } - - override DataFlow::Node getAnInput() { - result in [ - this.getArg(0), - // fromstring / XML - this.getArgByName("text"), - // fromstringlist - this.getArgByName("strings"), - // parse / parseid - this.getArgByName("source"), - ] - } - - DataFlow::Node getParserArg() { result in [this.getArg(1), this.getArgByName("parser")] } - - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { - this.getParserArg() = XMLParser::instanceVulnerableTo(kind) - or - kind.isXxe() and - not exists(this.getParserArg()) - } - - override predicate mayExecuteInput() { none() } - - override DataFlow::Node getOutput() { result = this } - } -} - private module Xmltodict { /** * A call to `xmltodict.parse`. diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/lxml_etree.py b/python/ql/test/library-tests/frameworks/lxml/parsing.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/XML/lxml_etree.py rename to python/ql/test/library-tests/frameworks/lxml/parsing.py diff --git a/python/ql/test/library-tests/frameworks/lxml/xpath.py b/python/ql/test/library-tests/frameworks/lxml/xpath.py index e8ce583503a..9cf3a0883bd 100644 --- a/python/ql/test/library-tests/frameworks/lxml/xpath.py +++ b/python/ql/test/library-tests/frameworks/lxml/xpath.py @@ -2,20 +2,20 @@ from lxml import etree from io import StringIO def test_parse(): - tree = etree.parse(StringIO('')) + tree = etree.parse(StringIO('')) # $ decodeFormat=XML decodeInput=StringIO(..) decodeOutput=etree.parse(..) xmlVuln='XXE' r = tree.xpath('/foo/bar') # $ getXPath='/foo/bar' def test_XPath_class(): - root = etree.XML("TEXT") + root = etree.XML("TEXT") # $ decodeFormat=XML decodeInput="TEXT" decodeOutput=etree.XML(..) xmlVuln='XXE' find_text = etree.XPath("path") # $ constructedXPath="path" text = find_text(root)[0] def test_ETXpath_class(): - root = etree.XML("TEXT") + root = etree.XML("TEXT") # $ decodeFormat=XML decodeInput="TEXT" decodeOutput=etree.XML(..) xmlVuln='XXE' find_text = etree.ETXPath("path") # $ constructedXPath="path" text = find_text(root)[0] def test_XPathEvaluator_class(): - root = etree.XML("TEXT") + root = etree.XML("TEXT") # $ decodeFormat=XML decodeInput="TEXT" decodeOutput=etree.XML(..) xmlVuln='XXE' search_root = etree.XPathEvaluator(root) text = search_root("path")[0] # $ getXPath="path" From 7f5f7679f8f9f14db7fac551bfb6071c08c41767 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 10:28:34 +0200 Subject: [PATCH 060/171] Python: Promote `xmltodict` modeling --- docs/codeql/support/reusables/frameworks.rst | 1 + python/ql/lib/semmle/python/Frameworks.qll | 1 + .../semmle/python/frameworks/Xmltodict.qll | 39 +++++++++++++++++++ .../semmle/python/frameworks/Xml.qll | 22 ----------- .../xmltodict/ConceptsTest.expected | 0 .../frameworks/xmltodict/ConceptsTest.ql | 2 + .../frameworks/xmltodict/test.py} | 0 7 files changed, 43 insertions(+), 22 deletions(-) create mode 100644 python/ql/lib/semmle/python/frameworks/Xmltodict.qll create mode 100644 python/ql/test/library-tests/frameworks/xmltodict/ConceptsTest.expected create mode 100644 python/ql/test/library-tests/frameworks/xmltodict/ConceptsTest.ql rename python/ql/test/{experimental/library-tests/frameworks/XML/xmltodict.py => library-tests/frameworks/xmltodict/test.py} (100%) diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst index 93280c6732a..12bcd5af8e6 100644 --- a/docs/codeql/support/reusables/frameworks.rst +++ b/docs/codeql/support/reusables/frameworks.rst @@ -214,3 +214,4 @@ Python built-in support libtaxii, TAXII utility library libxml2, XML processing library lxml, XML processing library + xmltodict, XML processing library diff --git a/python/ql/lib/semmle/python/Frameworks.qll b/python/ql/lib/semmle/python/Frameworks.qll index b94b8aee5d9..4812628d262 100644 --- a/python/ql/lib/semmle/python/Frameworks.qll +++ b/python/ql/lib/semmle/python/Frameworks.qll @@ -52,3 +52,4 @@ private import semmle.python.frameworks.Ujson private import semmle.python.frameworks.Urllib3 private import semmle.python.frameworks.Yaml private import semmle.python.frameworks.Yarl +private import semmle.python.frameworks.Xmltodict diff --git a/python/ql/lib/semmle/python/frameworks/Xmltodict.qll b/python/ql/lib/semmle/python/frameworks/Xmltodict.qll new file mode 100644 index 00000000000..bb65607251f --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/Xmltodict.qll @@ -0,0 +1,39 @@ +/** + * Provides classes modeling security-relevant aspects of the `xmltodict` PyPI package. + * + * See + * - https://pypi.org/project/xmltodict/ + */ + +private import python +private import semmle.python.dataflow.new.DataFlow +private import semmle.python.Concepts +private import semmle.python.ApiGraphs + +/** + * Provides classes modeling security-relevant aspects of the `xmltodict` PyPI package + * + * See + * - https://pypi.org/project/xmltodict/ + */ +private module Xmltodict { + /** + * A call to `xmltodict.parse`. + */ + private class XMLtoDictParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { + XMLtoDictParsing() { this = API::moduleImport("xmltodict").getMember("parse").getACall() } + + override DataFlow::Node getAnInput() { + result in [this.getArg(0), this.getArgByName("xml_input")] + } + + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and + this.getArgByName("disable_entities").getALocalSource().asExpr() = any(False f) + } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { result = this } + } +} diff --git a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll index b31151eed1a..c98370ba85a 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll @@ -333,25 +333,3 @@ private module SaxBasedParsing { override DataFlow::Node getOutput() { result = this } } } - -private module Xmltodict { - /** - * A call to `xmltodict.parse`. - */ - private class XMLtoDictParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { - XMLtoDictParsing() { this = API::moduleImport("xmltodict").getMember("parse").getACall() } - - override DataFlow::Node getAnInput() { - result in [this.getArg(0), this.getArgByName("xml_input")] - } - - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and - this.getArgByName("disable_entities").getALocalSource().asExpr() = any(False f) - } - - override predicate mayExecuteInput() { none() } - - override DataFlow::Node getOutput() { result = this } - } -} diff --git a/python/ql/test/library-tests/frameworks/xmltodict/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/xmltodict/ConceptsTest.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/frameworks/xmltodict/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/xmltodict/ConceptsTest.ql new file mode 100644 index 00000000000..b557a0bccb6 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/xmltodict/ConceptsTest.ql @@ -0,0 +1,2 @@ +import python +import experimental.meta.ConceptsTest diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xmltodict.py b/python/ql/test/library-tests/frameworks/xmltodict/test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/XML/xmltodict.py rename to python/ql/test/library-tests/frameworks/xmltodict/test.py From 64aa503cc3b6374744efbaa2d6f4c322d03a3faa Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 10:42:05 +0200 Subject: [PATCH 061/171] Python: Promote `xml.etree` modeling --- .../lib/semmle/python/frameworks/Stdlib.qll | 117 +++++++++++++++++ .../semmle/python/frameworks/Xml.qll | 118 +----------------- .../frameworks/stdlib/XPathExecution.py | 2 +- .../frameworks/stdlib}/xml_etree.py | 0 4 files changed, 119 insertions(+), 118 deletions(-) rename python/ql/test/{experimental/library-tests/frameworks/XML => library-tests/frameworks/stdlib}/xml_etree.py (100%) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 234a8802f0f..263cdfcd0b3 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3174,6 +3174,123 @@ private module StdlibPrivate { } } } + + // --------------------------------------------------------------------------- + // xml.etree + // --------------------------------------------------------------------------- + /** + * Provides models for `xml.etree` parsers + * + * See + * - https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.XMLParser + * - https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.XMLPullParser + */ + module XMLParser { + /** + * A source of instances of `xml.etree` parsers, extend this class to model new instances. + * + * This can include instantiations of the class, return values from function + * calls, or a special parameter that will be set when functions are called by an external + * library. + * + * Use the predicate `XMLParser::instance()` to get references to instances of `xml.etree` parsers. + */ + abstract class InstanceSource extends DataFlow::LocalSourceNode { } + + /** A direct instantiation of `xml.etree` parsers. */ + private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode { + ClassInstantiation() { + this = + API::moduleImport("xml") + .getMember("etree") + .getMember("ElementTree") + .getMember("XMLParser") + .getACall() + or + this = + API::moduleImport("xml") + .getMember("etree") + .getMember("ElementTree") + .getMember("XMLPullParser") + .getACall() + } + } + + /** Gets a reference to an `xml.etree` parser instance. */ + private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { + t.start() and + result instanceof InstanceSource + or + exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) + } + + /** Gets a reference to an `xml.etree` parser instance. */ + DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } + + /** + * A call to the `feed` method of an `xml.etree` parser. + */ + private class XMLEtreeParserFeedCall extends DataFlow::MethodCallNode, XML::XMLParsing::Range { + XMLEtreeParserFeedCall() { this.calls(instance(), "feed") } + + override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } + + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + kind.isBillionLaughs() or kind.isQuadraticBlowup() + } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { + exists(DataFlow::Node objRef | + DataFlow::localFlow(this.getObject(), objRef) and + result.(DataFlow::MethodCallNode).calls(objRef, "close") + ) + } + } + } + + /** + * A call to either of: + * - `xml.etree.ElementTree.fromstring` + * - `xml.etree.ElementTree.fromstringlist` + * - `xml.etree.ElementTree.XML` + * - `xml.etree.ElementTree.XMLID` + * - `xml.etree.ElementTree.parse` + * - `xml.etree.ElementTree.iterparse` + */ + private class XMLEtreeParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { + XMLEtreeParsing() { + this = + API::moduleImport("xml") + .getMember("etree") + .getMember("ElementTree") + .getMember(["fromstring", "fromstringlist", "XML", "XMLID", "parse", "iterparse"]) + .getACall() + } + + override DataFlow::Node getAnInput() { + result in [ + this.getArg(0), + // fromstring / XML / XMLID + this.getArgByName("text"), + // fromstringlist + this.getArgByName("sequence"), + // parse / iterparse + this.getArgByName("source"), + ] + } + + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + // note: it does not matter what `xml.etree` parser you are using, you cannot + // change the security features anyway :| + kind.isBillionLaughs() or kind.isQuadraticBlowup() + } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { result = this } + } } // --------------------------------------------------------------------------- diff --git a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll index c98370ba85a..88def863824 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll @@ -8,129 +8,13 @@ private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts private import semmle.python.ApiGraphs -private module XmlEtree { - /** - * Provides models for `xml.etree` parsers - * - * See - * - https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.XMLParser - * - https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.XMLPullParser - */ - module XMLParser { - /** - * A source of instances of `xml.etree` parsers, extend this class to model new instances. - * - * This can include instantiations of the class, return values from function - * calls, or a special parameter that will be set when functions are called by an external - * library. - * - * Use the predicate `XMLParser::instance()` to get references to instances of `xml.etree` parsers. - */ - abstract class InstanceSource extends DataFlow::LocalSourceNode { } - - /** A direct instantiation of `xml.etree` parsers. */ - private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode { - ClassInstantiation() { - this = - API::moduleImport("xml") - .getMember("etree") - .getMember("ElementTree") - .getMember("XMLParser") - .getACall() - or - this = - API::moduleImport("xml") - .getMember("etree") - .getMember("ElementTree") - .getMember("XMLPullParser") - .getACall() - } - } - - /** Gets a reference to an `xml.etree` parser instance. */ - private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { - t.start() and - result instanceof InstanceSource - or - exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) - } - - /** Gets a reference to an `xml.etree` parser instance. */ - DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } - - /** - * A call to the `feed` method of an `xml.etree` parser. - */ - private class XMLEtreeParserFeedCall extends DataFlow::MethodCallNode, XML::XMLParsing::Range { - XMLEtreeParserFeedCall() { this.calls(instance(), "feed") } - - override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } - - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { - kind.isBillionLaughs() or kind.isQuadraticBlowup() - } - - override predicate mayExecuteInput() { none() } - - override DataFlow::Node getOutput() { - exists(DataFlow::Node objRef | - DataFlow::localFlow(this.getObject(), objRef) and - result.(DataFlow::MethodCallNode).calls(objRef, "close") - ) - } - } - } - - /** - * A call to either of: - * - `xml.etree.ElementTree.fromstring` - * - `xml.etree.ElementTree.fromstringlist` - * - `xml.etree.ElementTree.XML` - * - `xml.etree.ElementTree.XMLID` - * - `xml.etree.ElementTree.parse` - * - `xml.etree.ElementTree.iterparse` - */ - private class XMLEtreeParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { - XMLEtreeParsing() { - this = - API::moduleImport("xml") - .getMember("etree") - .getMember("ElementTree") - .getMember(["fromstring", "fromstringlist", "XML", "XMLID", "parse", "iterparse"]) - .getACall() - } - - override DataFlow::Node getAnInput() { - result in [ - this.getArg(0), - // fromstring / XML / XMLID - this.getArgByName("text"), - // fromstringlist - this.getArgByName("sequence"), - // parse / iterparse - this.getArgByName("source"), - ] - } - - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { - // note: it does not matter what `xml.etree` parser you are using, you cannot - // change the security features anyway :| - kind.isBillionLaughs() or kind.isQuadraticBlowup() - } - - override predicate mayExecuteInput() { none() } - - override DataFlow::Node getOutput() { result = this } - } -} - private module SaxBasedParsing { /** * A call to the `setFeature` method on a XML sax parser. * * See https://docs.python.org/3.10/library/xml.sax.reader.html#xml.sax.xmlreader.XMLReader.setFeature */ - class SaxParserSetFeatureCall extends DataFlow::MethodCallNode { + private class SaxParserSetFeatureCall extends DataFlow::MethodCallNode { SaxParserSetFeatureCall() { this = API::moduleImport("xml") diff --git a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py index 98bdaefac27..d39b0e04888 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py +++ b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py @@ -2,7 +2,7 @@ match = "dc:title" ns = {'dc': 'http://purl.org/dc/elements/1.1/'} import xml.etree.ElementTree as ET -tree = ET.parse('country_data.xml') +tree = ET.parse('country_data.xml') # $ decodeFormat=XML decodeInput='country_data.xml' decodeOutput=ET.parse(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' root = tree.getroot() root.find(match, namespaces=ns) # $ getXPath=match diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xml_etree.py b/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/XML/xml_etree.py rename to python/ql/test/library-tests/frameworks/stdlib/xml_etree.py From a315aa84b2bdfad3cd3196336bbc1bc6fc658415 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 11:13:12 +0200 Subject: [PATCH 062/171] Python: Add some links in QLDocs --- python/ql/lib/semmle/python/frameworks/Lxml.qll | 7 ++++++- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index de89345a7d6..e1052efbf99 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -224,7 +224,12 @@ private module Lxml { * - `lxml.etree.parse` * - `lxml.etree.parseid` * - * See https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.fromstring + * See + * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.fromstring + * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.fromstringlist + * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.XML + * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parse + * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parseid */ private class LXMLParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { LXMLParsing() { diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 263cdfcd0b3..6c8de064852 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3258,6 +3258,14 @@ private module StdlibPrivate { * - `xml.etree.ElementTree.XMLID` * - `xml.etree.ElementTree.parse` * - `xml.etree.ElementTree.iterparse` + * + * See + * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.fromstring + * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.fromstringlist + * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.XML + * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.XMLID + * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.parse + * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.iterparse */ private class XMLEtreeParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { XMLEtreeParsing() { From 6774085e7af76b7faa952d2b23cbc9232a57273d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 11:19:25 +0200 Subject: [PATCH 063/171] Python: Add note about parseid/XMLID --- python/ql/lib/semmle/python/frameworks/Lxml.qll | 9 ++++++++- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index e1052efbf99..e090b9dbf05 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -263,6 +263,13 @@ private module Lxml { override predicate mayExecuteInput() { none() } - override DataFlow::Node getOutput() { result = this } + override DataFlow::Node getOutput() { + // Note: for `parseid` the result of the call is a tuple with `(root, dict)`, so + // maybe we should not just say that the entire tuple is the decoding output... my + // gut feeling is that THIS instance doesn't matter too much, but that it would be + // nice to be able to do this in general. (this is a problem for both `lxml.etree` + // and `xml.etree`) + result = this + } } } diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 6c8de064852..77ec1b5f9da 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3297,7 +3297,14 @@ private module StdlibPrivate { override predicate mayExecuteInput() { none() } - override DataFlow::Node getOutput() { result = this } + override DataFlow::Node getOutput() { + // Note: for `XMLID` the result of the call is a tuple with `(root, dict)`, so + // maybe we should not just say that the entire tuple is the decoding output... my + // gut feeling is that THIS instance doesn't matter too much, but that it would be + // nice to be able to do this in general. (this is a problem for both `lxml.etree` + // and `xml.etree`) + result = this + } } } From 12cbdcde284e4e8fbce7a02ae0f65cedeee7e4eb Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 11:21:24 +0200 Subject: [PATCH 064/171] Python: Model `lxml.etree.XMLID` --- python/ql/lib/semmle/python/frameworks/Lxml.qll | 8 +++++--- python/ql/test/library-tests/frameworks/lxml/parsing.py | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index e090b9dbf05..60cc850fd34 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -221,6 +221,7 @@ private module Lxml { * - `lxml.etree.fromstring` * - `lxml.etree.fromstringlist` * - `lxml.etree.XML` + * - `lxml.etree.XMLID` * - `lxml.etree.parse` * - `lxml.etree.parseid` * @@ -228,6 +229,7 @@ private module Lxml { * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.fromstring * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.fromstringlist * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.XML + * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.XMLID * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parse * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parseid */ @@ -236,14 +238,14 @@ private module Lxml { this = API::moduleImport("lxml") .getMember("etree") - .getMember(["fromstring", "fromstringlist", "XML", "parse", "parseid"]) + .getMember(["fromstring", "fromstringlist", "XML", "XMLID", "parse", "parseid"]) .getACall() } override DataFlow::Node getAnInput() { result in [ this.getArg(0), - // fromstring / XML + // fromstring / XML / XMLID this.getArgByName("text"), // fromstringlist this.getArgByName("strings"), @@ -264,7 +266,7 @@ private module Lxml { override predicate mayExecuteInput() { none() } override DataFlow::Node getOutput() { - // Note: for `parseid` the result of the call is a tuple with `(root, dict)`, so + // Note: for `parseid`/XMLID the result of the call is a tuple with `(root, dict)`, so // maybe we should not just say that the entire tuple is the decoding output... my // gut feeling is that THIS instance doesn't matter too much, but that it would be // nice to be able to do this in general. (this is a problem for both `lxml.etree` diff --git a/python/ql/test/library-tests/frameworks/lxml/parsing.py b/python/ql/test/library-tests/frameworks/lxml/parsing.py index f1dbd5390ad..e69a68a6ad2 100644 --- a/python/ql/test/library-tests/frameworks/lxml/parsing.py +++ b/python/ql/test/library-tests/frameworks/lxml/parsing.py @@ -13,6 +13,9 @@ lxml.etree.fromstringlist(strings=[x]) # $ decodeFormat=XML decodeInput=List xml lxml.etree.XML(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.XML(..) lxml.etree.XML(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.XML(..) +lxml.etree.XMLID(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.XMLID(..) +lxml.etree.XMLID(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.XMLID(..) + lxml.etree.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) lxml.etree.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) From 386ff5361415f17c248285300de71ca735e92f7a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 11:32:22 +0200 Subject: [PATCH 065/171] Python: Model `lxml.iterparse` --- .../ql/lib/semmle/python/frameworks/Lxml.qll | 30 +++++++++++++++++++ .../library-tests/frameworks/lxml/parsing.py | 18 ++++++++--- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index 60cc850fd34..821fc6bac80 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -274,4 +274,34 @@ private module Lxml { result = this } } + + /** + * A call to `lxml.etree.iterparse` + * + * See + * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.iterparse + */ + private class LXMLIterparseCall extends DataFlow::CallCfgNode, XML::XMLParsing::Range { + LXMLIterparseCall() { + this = API::moduleImport("lxml").getMember("etree").getMember("iterparse").getACall() + } + + override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("source")] } + + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + // note that there is no `resolve_entities` argument, so it's not possible to turn off XXE :O + kind.isXxe() + or + (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and + this.getArgByName("huge_tree").getALocalSource().asExpr() = any(True t) + or + kind.isDtdRetrieval() and + this.getArgByName("load_dtd").getALocalSource().asExpr() = any(True t) and + this.getArgByName("no_network").getALocalSource().asExpr() = any(False t) + } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { result = this } + } } diff --git a/python/ql/test/library-tests/frameworks/lxml/parsing.py b/python/ql/test/library-tests/frameworks/lxml/parsing.py index e69a68a6ad2..5abd626caf4 100644 --- a/python/ql/test/library-tests/frameworks/lxml/parsing.py +++ b/python/ql/test/library-tests/frameworks/lxml/parsing.py @@ -16,11 +16,15 @@ lxml.etree.XML(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOu lxml.etree.XMLID(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.XMLID(..) lxml.etree.XMLID(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.XMLID(..) -lxml.etree.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) -lxml.etree.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) +xml_file = 'xml_file' +lxml.etree.parse(xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) +lxml.etree.parse(source=xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) -lxml.etree.parseid(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XXE' decodeOutput=lxml.etree.parseid(..) -lxml.etree.parseid(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XXE' decodeOutput=lxml.etree.parseid(..) +lxml.etree.parseid(xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parseid(..) +lxml.etree.parseid(source=xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parseid(..) + +lxml.etree.iterparse(xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) +lxml.etree.iterparse(source=xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) # With default parsers (nothing changed) parser = lxml.etree.XMLParser() @@ -55,3 +59,9 @@ lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x decod # DTD retrival vuln (also XXE) parser = lxml.etree.XMLParser(load_dtd=True, no_network=False) lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVuln='DTD retrieval' xmlVuln='XXE' decodeOutput=lxml.etree.fromstring(..) + +# iterparse configurations ... this doesn't use a parser argument but takes MOST (!) of +# the normal XMLParser arguments. Specifically, it doesn't allow disabling XXE :O + +lxml.etree.iterparse(xml_file, huge_tree=True) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) +lxml.etree.iterparse(xml_file, load_dtd=True, no_network=False) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='DTD retrieval' xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) From 543454eff234ac2d403b932cb82b38309dea8002 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 11:47:29 +0200 Subject: [PATCH 066/171] Python: Model file access from XML parsing --- .../ql/lib/semmle/python/frameworks/Lxml.qll | 29 ++++++++++++++++++- .../lib/semmle/python/frameworks/Stdlib.qll | 29 +++++++++++++++++++ .../library-tests/frameworks/lxml/parsing.py | 16 +++++----- .../library-tests/frameworks/lxml/xpath.py | 2 +- .../frameworks/stdlib/XPathExecution.py | 2 +- .../frameworks/stdlib/xml_etree.py | 8 ++--- 6 files changed, 71 insertions(+), 15 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index 821fc6bac80..a3825a70db0 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -275,13 +275,38 @@ private module Lxml { } } + /** + * A call to `lxml.etree.ElementTree.parse` or `lxml.etree.ElementTree.parseid`, which + * takes either a filename or a file-like object as argument. To capture the filename + * for path-injection, we have this subclass. + * + * See + * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parse + * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parseid + */ + private class FileAccessFromLXMLParsing extends LXMLParsing, FileSystemAccess::Range { + FileAccessFromLXMLParsing() { + this = API::moduleImport("lxml").getMember("etree").getMember(["parse", "parseid"]).getACall() + // I considered whether we should try to reduce FPs from people passing file-like + // objects, which will not be a file system access (and couldn't cause a + // path-injection). + // + // I suppose that once we have proper flow-summary support for file-like objects, + // we can make the XXE/XML-bomb sinks allow an access-path, while the + // path-injection sink wouldn't, and then we will not end up with such FPs. + } + + override DataFlow::Node getAPathArgument() { result = this.getAnInput() } + } + /** * A call to `lxml.etree.iterparse` * * See * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.iterparse */ - private class LXMLIterparseCall extends DataFlow::CallCfgNode, XML::XMLParsing::Range { + private class LXMLIterparseCall extends DataFlow::CallCfgNode, XML::XMLParsing::Range, + FileSystemAccess::Range { LXMLIterparseCall() { this = API::moduleImport("lxml").getMember("etree").getMember("iterparse").getACall() } @@ -303,5 +328,7 @@ private module Lxml { override predicate mayExecuteInput() { none() } override DataFlow::Node getOutput() { result = this } + + override DataFlow::Node getAPathArgument() { result = this.getAnInput() } } } diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 77ec1b5f9da..3afbf71f495 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3306,6 +3306,35 @@ private module StdlibPrivate { result = this } } + + /** + * A call to `xml.etree.ElementTree.parse` or `xml.etree.ElementTree.iterparse`, which + * takes either a filename or a file-like object as argument. To capture the filename + * for path-injection, we have this subclass. + * + * See + * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.parse + * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.iterparse + */ + private class FileAccessFromXMLEtreeParsing extends XMLEtreeParsing, FileSystemAccess::Range { + FileAccessFromXMLEtreeParsing() { + this = + API::moduleImport("xml") + .getMember("etree") + .getMember("ElementTree") + .getMember(["parse", "iterparse"]) + .getACall() + // I considered whether we should try to reduce FPs from people passing file-like + // objects, which will not be a file system access (and couldn't cause a + // path-injection). + // + // I suppose that once we have proper flow-summary support for file-like objects, + // we can make the XXE/XML-bomb sinks allow an access-path, while the + // path-injection sink wouldn't, and then we will not end up with such FPs. + } + + override DataFlow::Node getAPathArgument() { result = this.getAnInput() } + } } // --------------------------------------------------------------------------- diff --git a/python/ql/test/library-tests/frameworks/lxml/parsing.py b/python/ql/test/library-tests/frameworks/lxml/parsing.py index 5abd626caf4..ca68c99a90e 100644 --- a/python/ql/test/library-tests/frameworks/lxml/parsing.py +++ b/python/ql/test/library-tests/frameworks/lxml/parsing.py @@ -17,14 +17,14 @@ lxml.etree.XMLID(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutpu lxml.etree.XMLID(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XXE' decodeOutput=lxml.etree.XMLID(..) xml_file = 'xml_file' -lxml.etree.parse(xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) -lxml.etree.parse(source=xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) +lxml.etree.parse(xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) getAPathArgument=xml_file +lxml.etree.parse(source=xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parse(..) getAPathArgument=xml_file -lxml.etree.parseid(xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parseid(..) -lxml.etree.parseid(source=xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parseid(..) +lxml.etree.parseid(xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parseid(..) getAPathArgument=xml_file +lxml.etree.parseid(source=xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.parseid(..) getAPathArgument=xml_file -lxml.etree.iterparse(xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) -lxml.etree.iterparse(source=xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) +lxml.etree.iterparse(xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) getAPathArgument=xml_file +lxml.etree.iterparse(source=xml_file) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) getAPathArgument=xml_file # With default parsers (nothing changed) parser = lxml.etree.XMLParser() @@ -63,5 +63,5 @@ lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVu # iterparse configurations ... this doesn't use a parser argument but takes MOST (!) of # the normal XMLParser arguments. Specifically, it doesn't allow disabling XXE :O -lxml.etree.iterparse(xml_file, huge_tree=True) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) -lxml.etree.iterparse(xml_file, load_dtd=True, no_network=False) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='DTD retrieval' xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) +lxml.etree.iterparse(xml_file, huge_tree=True) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) getAPathArgument=xml_file +lxml.etree.iterparse(xml_file, load_dtd=True, no_network=False) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='DTD retrieval' xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) getAPathArgument=xml_file diff --git a/python/ql/test/library-tests/frameworks/lxml/xpath.py b/python/ql/test/library-tests/frameworks/lxml/xpath.py index 9cf3a0883bd..f67c8dae17c 100644 --- a/python/ql/test/library-tests/frameworks/lxml/xpath.py +++ b/python/ql/test/library-tests/frameworks/lxml/xpath.py @@ -2,7 +2,7 @@ from lxml import etree from io import StringIO def test_parse(): - tree = etree.parse(StringIO('')) # $ decodeFormat=XML decodeInput=StringIO(..) decodeOutput=etree.parse(..) xmlVuln='XXE' + tree = etree.parse(StringIO('')) # $ decodeFormat=XML decodeInput=StringIO(..) decodeOutput=etree.parse(..) xmlVuln='XXE' getAPathArgument=StringIO(..) r = tree.xpath('/foo/bar') # $ getXPath='/foo/bar' def test_XPath_class(): diff --git a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py index d39b0e04888..b501e2d4ccb 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py +++ b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py @@ -2,7 +2,7 @@ match = "dc:title" ns = {'dc': 'http://purl.org/dc/elements/1.1/'} import xml.etree.ElementTree as ET -tree = ET.parse('country_data.xml') # $ decodeFormat=XML decodeInput='country_data.xml' decodeOutput=ET.parse(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +tree = ET.parse('country_data.xml') # $ decodeFormat=XML decodeInput='country_data.xml' decodeOutput=ET.parse(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument='country_data.xml' root = tree.getroot() root.find(match, namespaces=ns) # $ getXPath=match diff --git a/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py b/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py index 0ed750ba8c7..684aaaa4a9c 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py +++ b/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py @@ -16,11 +16,11 @@ xml.etree.ElementTree.XML(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Bi xml.etree.ElementTree.XMLID(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.XMLID(..) xml.etree.ElementTree.XMLID(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.XMLID(..) -xml.etree.ElementTree.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.parse(..) -xml.etree.ElementTree.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.parse(..) +xml.etree.ElementTree.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.parse(..) getAPathArgument=StringIO(..) +xml.etree.ElementTree.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.parse(..) getAPathArgument=StringIO(..) -xml.etree.ElementTree.iterparse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.iterparse(..) -xml.etree.ElementTree.iterparse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.iterparse(..) +xml.etree.ElementTree.iterparse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.iterparse(..) getAPathArgument=StringIO(..) +xml.etree.ElementTree.iterparse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.iterparse(..) getAPathArgument=StringIO(..) # With parsers (no options available to disable/enable security features) From db43d043c4cdd59c65424f20fdcdc0a7d79a632c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 11:54:08 +0200 Subject: [PATCH 067/171] Python: Add test showing misalignment of xml.etree modeling --- .../test/library-tests/frameworks/stdlib/XPathExecution.py | 5 +++++ python/ql/test/library-tests/frameworks/stdlib/xml_etree.py | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py index b501e2d4ccb..37043d7049c 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py +++ b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py @@ -15,3 +15,8 @@ tree.parse("index.xhtml") tree.find(match, namespaces=ns) # $ getXPath=match tree.findall(match, namespaces=ns) # $ getXPath=match tree.findtext(match, default=None, namespaces=ns) # $ getXPath=match + +parser = ET.XMLParser() +parser.feed("bar") # $ decodeFormat=XML decodeInput="bar" xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +tree = parser.close() # $ decodeOutput=parser.close() +tree.find(match, namespaces=ns) # $ MISSING: getXPath=match diff --git a/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py b/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py index 684aaaa4a9c..da04cedbdfc 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py +++ b/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py @@ -22,6 +22,10 @@ xml.etree.ElementTree.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput xml.etree.ElementTree.iterparse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.iterparse(..) getAPathArgument=StringIO(..) xml.etree.ElementTree.iterparse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.iterparse(..) getAPathArgument=StringIO(..) +tree = xml.etree.ElementTree.ElementTree() +tree.parse("file.xml") # $ MISSING: decodeFormat=XML decodeInput="file.xml" xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=tree.parse(..) getAPathArgument="file.xml" +tree.parse(source="file.xml") # $ MISSING: decodeFormat=XML decodeInput="file.xml" xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=tree.parse(..) getAPathArgument="file.xml" + # With parsers (no options available to disable/enable security features) parser = xml.etree.ElementTree.XMLParser() From 70b3eecdd506fcb2e17f3eb027e7b05073c257df Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 17:13:11 +0200 Subject: [PATCH 068/171] Python: Merge `xml.etree.ElementTree` models I forgot about the existing ones when I promoted it --- .../lib/semmle/python/frameworks/Stdlib.qll | 127 +++++++++--------- 1 file changed, 62 insertions(+), 65 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 3afbf71f495..85cf61cdbaf 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -2835,70 +2835,6 @@ private module StdlibPrivate { override string getKind() { result = Escaping::getRegexKind() } } - // --------------------------------------------------------------------------- - // xml.etree.ElementTree - // --------------------------------------------------------------------------- - /** - * An instance of `xml.etree.ElementTree.ElementTree`. - * - * See https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.ElementTree - */ - private API::Node elementTreeInstance() { - //parse to a tree - result = - API::moduleImport("xml") - .getMember("etree") - .getMember("ElementTree") - .getMember("parse") - .getReturn() - or - // construct a tree without parsing - result = - API::moduleImport("xml") - .getMember("etree") - .getMember("ElementTree") - .getMember("ElementTree") - .getReturn() - } - - /** - * An instance of `xml.etree.ElementTree.Element`. - * - * See https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element - */ - private API::Node elementInstance() { - // parse or go to the root of a tree - result = elementTreeInstance().getMember(["parse", "getroot"]).getReturn() - or - // parse directly to an element - result = - API::moduleImport("xml") - .getMember("etree") - .getMember("ElementTree") - .getMember(["fromstring", "fromstringlist", "XML"]) - .getReturn() - } - - /** - * A call to a find method on a tree or an element will execute an XPath expression. - */ - private class ElementTreeFindCall extends XML::XPathExecution::Range, DataFlow::CallCfgNode { - string methodName; - - ElementTreeFindCall() { - methodName in ["find", "findall", "findtext"] and - ( - this = elementTreeInstance().getMember(methodName).getACall() - or - this = elementInstance().getMember(methodName).getACall() - ) - } - - override DataFlow::Node getXPath() { result in [this.getArg(0), this.getArgByName("match")] } - - override string getName() { result = "xml.etree" } - } - // --------------------------------------------------------------------------- // urllib // --------------------------------------------------------------------------- @@ -3176,8 +3112,69 @@ private module StdlibPrivate { } // --------------------------------------------------------------------------- - // xml.etree + // xml.etree.ElementTree // --------------------------------------------------------------------------- + /** + * An instance of `xml.etree.ElementTree.ElementTree`. + * + * See https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.ElementTree + */ + private API::Node elementTreeInstance() { + //parse to a tree + result = + API::moduleImport("xml") + .getMember("etree") + .getMember("ElementTree") + .getMember("parse") + .getReturn() + or + // construct a tree without parsing + result = + API::moduleImport("xml") + .getMember("etree") + .getMember("ElementTree") + .getMember("ElementTree") + .getReturn() + } + + /** + * An instance of `xml.etree.ElementTree.Element`. + * + * See https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element + */ + private API::Node elementInstance() { + // parse or go to the root of a tree + result = elementTreeInstance().getMember(["parse", "getroot"]).getReturn() + or + // parse directly to an element + result = + API::moduleImport("xml") + .getMember("etree") + .getMember("ElementTree") + .getMember(["fromstring", "fromstringlist", "XML"]) + .getReturn() + } + + /** + * A call to a find method on a tree or an element will execute an XPath expression. + */ + private class ElementTreeFindCall extends XML::XPathExecution::Range, DataFlow::CallCfgNode { + string methodName; + + ElementTreeFindCall() { + methodName in ["find", "findall", "findtext"] and + ( + this = elementTreeInstance().getMember(methodName).getACall() + or + this = elementInstance().getMember(methodName).getACall() + ) + } + + override DataFlow::Node getXPath() { result in [this.getArg(0), this.getArgByName("match")] } + + override string getName() { result = "xml.etree" } + } + /** * Provides models for `xml.etree` parsers * From 05bb0ef97688627eacd4b6ed247b84a707385ed5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 17:24:16 +0200 Subject: [PATCH 069/171] Python: Align `xml.etree.ElementTree` modeling I didn't find a good way to actually share the stuff, so we kinda just have 2 things that look very similar :| --- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 14 ++++++++++++++ .../frameworks/stdlib/XPathExecution.py | 4 ++-- .../library-tests/frameworks/stdlib/xml_etree.py | 4 ++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 85cf61cdbaf..1118133d215 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3153,6 +3153,15 @@ private module StdlibPrivate { .getMember("ElementTree") .getMember(["fromstring", "fromstringlist", "XML"]) .getReturn() + or + result = + API::moduleImport("xml") + .getMember("etree") + .getMember("ElementTree") + .getMember("XMLParser") + .getReturn() + .getMember("close") + .getReturn() } /** @@ -3255,6 +3264,7 @@ private module StdlibPrivate { * - `xml.etree.ElementTree.XMLID` * - `xml.etree.ElementTree.parse` * - `xml.etree.ElementTree.iterparse` + * - `parse` method on an `xml.etree.ElementTree.ElementTree` instance * * See * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.fromstring @@ -3272,6 +3282,8 @@ private module StdlibPrivate { .getMember("ElementTree") .getMember(["fromstring", "fromstringlist", "XML", "XMLID", "parse", "iterparse"]) .getACall() + or + this = elementTreeInstance().getMember("parse").getACall() } override DataFlow::Node getAnInput() { @@ -3321,6 +3333,8 @@ private module StdlibPrivate { .getMember("ElementTree") .getMember(["parse", "iterparse"]) .getACall() + or + this = elementTreeInstance().getMember("parse").getACall() // I considered whether we should try to reduce FPs from people passing file-like // objects, which will not be a file system access (and couldn't cause a // path-injection). diff --git a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py index 37043d7049c..5faff5ed868 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py +++ b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py @@ -10,7 +10,7 @@ root.findall(match, namespaces=ns) # $ getXPath=match root.findtext(match, default=None, namespaces=ns) # $ getXPath=match tree = ET.ElementTree() -tree.parse("index.xhtml") +tree.parse("index.xhtml") # $ decodeFormat=XML decodeInput="index.xhtml" decodeOutput=tree.parse(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument="index.xhtml" tree.find(match, namespaces=ns) # $ getXPath=match tree.findall(match, namespaces=ns) # $ getXPath=match @@ -19,4 +19,4 @@ tree.findtext(match, default=None, namespaces=ns) # $ getXPath=match parser = ET.XMLParser() parser.feed("bar") # $ decodeFormat=XML decodeInput="bar" xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' tree = parser.close() # $ decodeOutput=parser.close() -tree.find(match, namespaces=ns) # $ MISSING: getXPath=match +tree.find(match, namespaces=ns) # $ getXPath=match diff --git a/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py b/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py index da04cedbdfc..00f3b964b18 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py +++ b/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py @@ -23,8 +23,8 @@ xml.etree.ElementTree.iterparse(StringIO(x)) # $ decodeFormat=XML decodeInput=St xml.etree.ElementTree.iterparse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.iterparse(..) getAPathArgument=StringIO(..) tree = xml.etree.ElementTree.ElementTree() -tree.parse("file.xml") # $ MISSING: decodeFormat=XML decodeInput="file.xml" xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=tree.parse(..) getAPathArgument="file.xml" -tree.parse(source="file.xml") # $ MISSING: decodeFormat=XML decodeInput="file.xml" xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=tree.parse(..) getAPathArgument="file.xml" +tree.parse("file.xml") # $ decodeFormat=XML decodeInput="file.xml" xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=tree.parse(..) getAPathArgument="file.xml" +tree.parse(source="file.xml") # $ decodeFormat=XML decodeInput="file.xml" xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=tree.parse(..) getAPathArgument="file.xml" # With parsers (no options available to disable/enable security features) From e11269715dc55e3509625489267601b736c324f1 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 17:44:00 +0200 Subject: [PATCH 070/171] Python: Promote `xml.sax` and `xml.dom.*` modeling --- .../lib/semmle/python/frameworks/Stdlib.qll | 214 ++++++++++++++++++ .../semmle/python/frameworks/Xml.qll | 210 ----------------- .../frameworks/stdlib}/xml_dom.py | 0 .../frameworks/stdlib}/xml_sax.py | 0 4 files changed, 214 insertions(+), 210 deletions(-) rename python/ql/test/{experimental/library-tests/frameworks/XML => library-tests/frameworks/stdlib}/xml_dom.py (100%) rename python/ql/test/{experimental/library-tests/frameworks/XML => library-tests/frameworks/stdlib}/xml_sax.py (100%) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 1118133d215..418f3475c1e 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3346,6 +3346,220 @@ private module StdlibPrivate { override DataFlow::Node getAPathArgument() { result = this.getAnInput() } } + + // --------------------------------------------------------------------------- + // xml.sax + // --------------------------------------------------------------------------- + /** + * A call to the `setFeature` method on a XML sax parser. + * + * See https://docs.python.org/3.10/library/xml.sax.reader.html#xml.sax.xmlreader.XMLReader.setFeature + */ + private class SaxParserSetFeatureCall extends DataFlow::MethodCallNode { + SaxParserSetFeatureCall() { + this = + API::moduleImport("xml") + .getMember("sax") + .getMember("make_parser") + .getReturn() + .getMember("setFeature") + .getACall() + } + + // The keyword argument names does not match documentation. I checked (with Python + // 3.9.5) that the names used here actually works. + DataFlow::Node getFeatureArg() { result in [this.getArg(0), this.getArgByName("name")] } + + DataFlow::Node getStateArg() { result in [this.getArg(1), this.getArgByName("state")] } + } + + /** Gets a back-reference to the `setFeature` state argument `arg`. */ + private DataFlow::TypeTrackingNode saxParserSetFeatureStateArgBacktracker( + DataFlow::TypeBackTracker t, DataFlow::Node arg + ) { + t.start() and + arg = any(SaxParserSetFeatureCall c).getStateArg() and + result = arg.getALocalSource() + or + exists(DataFlow::TypeBackTracker t2 | + result = saxParserSetFeatureStateArgBacktracker(t2, arg).backtrack(t2, t) + ) + } + + /** Gets a back-reference to the `setFeature` state argument `arg`. */ + DataFlow::LocalSourceNode saxParserSetFeatureStateArgBacktracker(DataFlow::Node arg) { + result = saxParserSetFeatureStateArgBacktracker(DataFlow::TypeBackTracker::end(), arg) + } + + /** + * Gets a reference to a XML sax parser that has `feature_external_ges` turned on. + * + * See https://docs.python.org/3/library/xml.sax.handler.html#xml.sax.handler.feature_external_ges + */ + private DataFlow::Node saxParserWithFeatureExternalGesTurnedOn(DataFlow::TypeTracker t) { + t.start() and + exists(SaxParserSetFeatureCall call | + call.getFeatureArg() = + API::moduleImport("xml") + .getMember("sax") + .getMember("handler") + .getMember("feature_external_ges") + .getAUse() and + saxParserSetFeatureStateArgBacktracker(call.getStateArg()) + .asExpr() + .(BooleanLiteral) + .booleanValue() = true and + result = call.getObject() + ) + or + exists(DataFlow::TypeTracker t2 | + t = t2.smallstep(saxParserWithFeatureExternalGesTurnedOn(t2), result) + ) and + // take account of that we can set the feature to False, which makes the parser safe again + not exists(SaxParserSetFeatureCall call | + call.getObject() = result and + call.getFeatureArg() = + API::moduleImport("xml") + .getMember("sax") + .getMember("handler") + .getMember("feature_external_ges") + .getAUse() and + saxParserSetFeatureStateArgBacktracker(call.getStateArg()) + .asExpr() + .(BooleanLiteral) + .booleanValue() = false + ) + } + + /** + * Gets a reference to a XML sax parser that has `feature_external_ges` turned on. + * + * See https://docs.python.org/3/library/xml.sax.handler.html#xml.sax.handler.feature_external_ges + */ + DataFlow::Node saxParserWithFeatureExternalGesTurnedOn() { + result = saxParserWithFeatureExternalGesTurnedOn(DataFlow::TypeTracker::end()) + } + + /** + * A call to the `parse` method on a SAX XML parser. + */ + private class XMLSaxInstanceParsing extends DataFlow::MethodCallNode, XML::XMLParsing::Range { + XMLSaxInstanceParsing() { + this = + API::moduleImport("xml") + .getMember("sax") + .getMember("make_parser") + .getReturn() + .getMember("parse") + .getACall() + } + + override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("source")] } + + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + // always vuln to these + (kind.isBillionLaughs() or kind.isQuadraticBlowup()) + or + // can be vuln to other things if features has been turned on + this.getObject() = saxParserWithFeatureExternalGesTurnedOn() and + (kind.isXxe() or kind.isDtdRetrieval()) + } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { + // note: the output of parsing with SAX is that the content handler gets the + // data... but we don't currently model this (it's not trivial to do, and won't + // really give us any value, at least not as of right now). + none() + } + } + + /** + * A call to either `parse` or `parseString` from `xml.sax` module. + * + * See: + * - https://docs.python.org/3.10/library/xml.sax.html#xml.sax.parse + * - https://docs.python.org/3.10/library/xml.sax.html#xml.sax.parseString + */ + private class XMLSaxParsing extends DataFlow::MethodCallNode, XML::XMLParsing::Range { + XMLSaxParsing() { + this = + API::moduleImport("xml").getMember("sax").getMember(["parse", "parseString"]).getACall() + } + + override DataFlow::Node getAnInput() { + result in [ + this.getArg(0), + // parseString + this.getArgByName("string"), + // parse + this.getArgByName("source"), + ] + } + + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + // always vuln to these + (kind.isBillionLaughs() or kind.isQuadraticBlowup()) + or + // can be vuln to other things if features has been turned on + this.getObject() = saxParserWithFeatureExternalGesTurnedOn() and + (kind.isXxe() or kind.isDtdRetrieval()) + } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { + // note: the output of parsing with SAX is that the content handler gets the + // data... but we don't currently model this (it's not trivial to do, and won't + // really give us any value, at least not as of right now). + none() + } + } + + // --------------------------------------------------------------------------- + // xml.dom.* + // --------------------------------------------------------------------------- + /** + * A call to the `parse` or `parseString` methods from `xml.dom.minidom` or `xml.dom.pulldom`. + * + * Both of these modules are based on SAX parsers. + */ + private class XMLDomParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { + XMLDomParsing() { + this = + API::moduleImport("xml") + .getMember("dom") + .getMember(["minidom", "pulldom"]) + .getMember(["parse", "parseString"]) + .getACall() + } + + override DataFlow::Node getAnInput() { + result in [ + this.getArg(0), + // parseString + this.getArgByName("string"), + // minidom.parse + this.getArgByName("file"), + // pulldom.parse + this.getArgByName("stream_or_string"), + ] + } + + DataFlow::Node getParserArg() { result in [this.getArg(1), this.getArgByName("parser")] } + + override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + this.getParserArg() = saxParserWithFeatureExternalGesTurnedOn() and + (kind.isXxe() or kind.isDtdRetrieval()) + or + (kind.isBillionLaughs() or kind.isQuadraticBlowup()) + } + + override predicate mayExecuteInput() { none() } + + override DataFlow::Node getOutput() { result = this } + } } // --------------------------------------------------------------------------- diff --git a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll index 88def863824..344a19a0109 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll @@ -7,213 +7,3 @@ private import python private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts private import semmle.python.ApiGraphs - -private module SaxBasedParsing { - /** - * A call to the `setFeature` method on a XML sax parser. - * - * See https://docs.python.org/3.10/library/xml.sax.reader.html#xml.sax.xmlreader.XMLReader.setFeature - */ - private class SaxParserSetFeatureCall extends DataFlow::MethodCallNode { - SaxParserSetFeatureCall() { - this = - API::moduleImport("xml") - .getMember("sax") - .getMember("make_parser") - .getReturn() - .getMember("setFeature") - .getACall() - } - - // The keyword argument names does not match documentation. I checked (with Python - // 3.9.5) that the names used here actually works. - DataFlow::Node getFeatureArg() { result in [this.getArg(0), this.getArgByName("name")] } - - DataFlow::Node getStateArg() { result in [this.getArg(1), this.getArgByName("state")] } - } - - /** Gets a back-reference to the `setFeature` state argument `arg`. */ - private DataFlow::TypeTrackingNode saxParserSetFeatureStateArgBacktracker( - DataFlow::TypeBackTracker t, DataFlow::Node arg - ) { - t.start() and - arg = any(SaxParserSetFeatureCall c).getStateArg() and - result = arg.getALocalSource() - or - exists(DataFlow::TypeBackTracker t2 | - result = saxParserSetFeatureStateArgBacktracker(t2, arg).backtrack(t2, t) - ) - } - - /** Gets a back-reference to the `setFeature` state argument `arg`. */ - DataFlow::LocalSourceNode saxParserSetFeatureStateArgBacktracker(DataFlow::Node arg) { - result = saxParserSetFeatureStateArgBacktracker(DataFlow::TypeBackTracker::end(), arg) - } - - /** - * Gets a reference to a XML sax parser that has `feature_external_ges` turned on. - * - * See https://docs.python.org/3/library/xml.sax.handler.html#xml.sax.handler.feature_external_ges - */ - private DataFlow::Node saxParserWithFeatureExternalGesTurnedOn(DataFlow::TypeTracker t) { - t.start() and - exists(SaxParserSetFeatureCall call | - call.getFeatureArg() = - API::moduleImport("xml") - .getMember("sax") - .getMember("handler") - .getMember("feature_external_ges") - .getAUse() and - saxParserSetFeatureStateArgBacktracker(call.getStateArg()) - .asExpr() - .(BooleanLiteral) - .booleanValue() = true and - result = call.getObject() - ) - or - exists(DataFlow::TypeTracker t2 | - t = t2.smallstep(saxParserWithFeatureExternalGesTurnedOn(t2), result) - ) and - // take account of that we can set the feature to False, which makes the parser safe again - not exists(SaxParserSetFeatureCall call | - call.getObject() = result and - call.getFeatureArg() = - API::moduleImport("xml") - .getMember("sax") - .getMember("handler") - .getMember("feature_external_ges") - .getAUse() and - saxParserSetFeatureStateArgBacktracker(call.getStateArg()) - .asExpr() - .(BooleanLiteral) - .booleanValue() = false - ) - } - - /** - * Gets a reference to a XML sax parser that has `feature_external_ges` turned on. - * - * See https://docs.python.org/3/library/xml.sax.handler.html#xml.sax.handler.feature_external_ges - */ - DataFlow::Node saxParserWithFeatureExternalGesTurnedOn() { - result = saxParserWithFeatureExternalGesTurnedOn(DataFlow::TypeTracker::end()) - } - - /** - * A call to the `parse` method on a SAX XML parser. - */ - private class XMLSaxInstanceParsing extends DataFlow::MethodCallNode, XML::XMLParsing::Range { - XMLSaxInstanceParsing() { - this = - API::moduleImport("xml") - .getMember("sax") - .getMember("make_parser") - .getReturn() - .getMember("parse") - .getACall() - } - - override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("source")] } - - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { - // always vuln to these - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) - or - // can be vuln to other things if features has been turned on - this.getObject() = saxParserWithFeatureExternalGesTurnedOn() and - (kind.isXxe() or kind.isDtdRetrieval()) - } - - override predicate mayExecuteInput() { none() } - - override DataFlow::Node getOutput() { - // note: the output of parsing with SAX is that the content handler gets the - // data... but we don't currently model this (it's not trivial to do, and won't - // really give us any value, at least not as of right now). - none() - } - } - - /** - * A call to either `parse` or `parseString` from `xml.sax` module. - * - * See: - * - https://docs.python.org/3.10/library/xml.sax.html#xml.sax.parse - * - https://docs.python.org/3.10/library/xml.sax.html#xml.sax.parseString - */ - private class XMLSaxParsing extends DataFlow::MethodCallNode, XML::XMLParsing::Range { - XMLSaxParsing() { - this = - API::moduleImport("xml").getMember("sax").getMember(["parse", "parseString"]).getACall() - } - - override DataFlow::Node getAnInput() { - result in [ - this.getArg(0), - // parseString - this.getArgByName("string"), - // parse - this.getArgByName("source"), - ] - } - - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { - // always vuln to these - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) - or - // can be vuln to other things if features has been turned on - this.getObject() = saxParserWithFeatureExternalGesTurnedOn() and - (kind.isXxe() or kind.isDtdRetrieval()) - } - - override predicate mayExecuteInput() { none() } - - override DataFlow::Node getOutput() { - // note: the output of parsing with SAX is that the content handler gets the - // data... but we don't currently model this (it's not trivial to do, and won't - // really give us any value, at least not as of right now). - none() - } - } - - /** - * A call to the `parse` or `parseString` methods from `xml.dom.minidom` or `xml.dom.pulldom`. - * - * Both of these modules are based on SAX parsers. - */ - private class XMLDomParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { - XMLDomParsing() { - this = - API::moduleImport("xml") - .getMember("dom") - .getMember(["minidom", "pulldom"]) - .getMember(["parse", "parseString"]) - .getACall() - } - - override DataFlow::Node getAnInput() { - result in [ - this.getArg(0), - // parseString - this.getArgByName("string"), - // minidom.parse - this.getArgByName("file"), - // pulldom.parse - this.getArgByName("stream_or_string"), - ] - } - - DataFlow::Node getParserArg() { result in [this.getArg(1), this.getArgByName("parser")] } - - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { - this.getParserArg() = saxParserWithFeatureExternalGesTurnedOn() and - (kind.isXxe() or kind.isDtdRetrieval()) - or - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) - } - - override predicate mayExecuteInput() { none() } - - override DataFlow::Node getOutput() { result = this } - } -} diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xml_dom.py b/python/ql/test/library-tests/frameworks/stdlib/xml_dom.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/XML/xml_dom.py rename to python/ql/test/library-tests/frameworks/stdlib/xml_dom.py diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/xml_sax.py b/python/ql/test/library-tests/frameworks/stdlib/xml_sax.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/XML/xml_sax.py rename to python/ql/test/library-tests/frameworks/stdlib/xml_sax.py From 1d7cec60ae09489618b7e561845b5a361c274583 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 17:50:23 +0200 Subject: [PATCH 071/171] Python: `xml.sax.parse` is not a method call And it's not possible to provide a parser argument either --- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 418f3475c1e..5659c7c8e91 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3482,7 +3482,7 @@ private module StdlibPrivate { * - https://docs.python.org/3.10/library/xml.sax.html#xml.sax.parse * - https://docs.python.org/3.10/library/xml.sax.html#xml.sax.parseString */ - private class XMLSaxParsing extends DataFlow::MethodCallNode, XML::XMLParsing::Range { + private class XMLSaxParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { XMLSaxParsing() { this = API::moduleImport("xml").getMember("sax").getMember(["parse", "parseString"]).getACall() @@ -3501,10 +3501,6 @@ private module StdlibPrivate { override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { // always vuln to these (kind.isBillionLaughs() or kind.isQuadraticBlowup()) - or - // can be vuln to other things if features has been turned on - this.getObject() = saxParserWithFeatureExternalGesTurnedOn() and - (kind.isXxe() or kind.isDtdRetrieval()) } override predicate mayExecuteInput() { none() } From b4c0065aeb160839129d25cc3ee1818564670d21 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 18:03:35 +0200 Subject: [PATCH 072/171] Python: Extend FileSystemAccess for `xml.sax` and `xml.dom.*` parsing --- .../lib/semmle/python/frameworks/Stdlib.qll | 72 ++++++++++++++++++- .../frameworks/stdlib/xml_dom.py | 16 ++--- .../frameworks/stdlib/xml_sax.py | 22 +++--- 3 files changed, 90 insertions(+), 20 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 5659c7c8e91..38fe32a3b3c 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3442,8 +3442,11 @@ private module StdlibPrivate { /** * A call to the `parse` method on a SAX XML parser. + * + * See https://docs.python.org/3/library/xml.sax.reader.html#xml.sax.xmlreader.XMLReader.parse */ - private class XMLSaxInstanceParsing extends DataFlow::MethodCallNode, XML::XMLParsing::Range { + private class XMLSaxInstanceParsing extends DataFlow::MethodCallNode, XML::XMLParsing::Range, + FileSystemAccess::Range { XMLSaxInstanceParsing() { this = API::moduleImport("xml") @@ -3473,6 +3476,17 @@ private module StdlibPrivate { // really give us any value, at least not as of right now). none() } + + override DataFlow::Node getAPathArgument() { + // I considered whether we should try to reduce FPs from people passing file-like + // objects, which will not be a file system access (and couldn't cause a + // path-injection). + // + // I suppose that once we have proper flow-summary support for file-like objects, + // we can make the XXE/XML-bomb sinks allow an access-path, while the + // path-injection sink wouldn't, and then we will not end up with such FPs. + result = this.getAnInput() + } } /** @@ -3513,6 +3527,29 @@ private module StdlibPrivate { } } + /** + * A call to `xml.sax.parse`, which takes either a filename or a file-like object as + * argument. To capture the filename for path-injection, we have this subclass. + * + * See + * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.parse + * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.iterparse + */ + private class FileAccessFromXMLSaxParsing extends XMLSaxParsing, FileSystemAccess::Range { + FileAccessFromXMLSaxParsing() { + this = API::moduleImport("xml").getMember("sax").getMember("parse").getACall() + // I considered whether we should try to reduce FPs from people passing file-like + // objects, which will not be a file system access (and couldn't cause a + // path-injection). + // + // I suppose that once we have proper flow-summary support for file-like objects, + // we can make the XXE/XML-bomb sinks allow an access-path, while the + // path-injection sink wouldn't, and then we will not end up with such FPs. + } + + override DataFlow::Node getAPathArgument() { result = this.getAnInput() } + } + // --------------------------------------------------------------------------- // xml.dom.* // --------------------------------------------------------------------------- @@ -3520,6 +3557,10 @@ private module StdlibPrivate { * A call to the `parse` or `parseString` methods from `xml.dom.minidom` or `xml.dom.pulldom`. * * Both of these modules are based on SAX parsers. + * + * See + * - https://docs.python.org/3/library/xml.dom.minidom.html#xml.dom.minidom.parse + * - https://docs.python.org/3/library/xml.dom.pulldom.html#xml.dom.pulldom.parse */ private class XMLDomParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { XMLDomParsing() { @@ -3556,6 +3597,35 @@ private module StdlibPrivate { override DataFlow::Node getOutput() { result = this } } + + /** + * A call to the `parse` or `parseString` methods from `xml.dom.minidom` or + * `xml.dom.pulldom`, which takes either a filename or a file-like object as argument. + * To capture the filename for path-injection, we have this subclass. + * + * See + * - https://docs.python.org/3/library/xml.dom.minidom.html#xml.dom.minidom.parse + * - https://docs.python.org/3/library/xml.dom.pulldom.html#xml.dom.pulldom.parse + */ + private class FileAccessFromXMLDomParsing extends XMLDomParsing, FileSystemAccess::Range { + FileAccessFromXMLDomParsing() { + this = + API::moduleImport("xml") + .getMember("dom") + .getMember(["minidom", "pulldom"]) + .getMember("parse") + .getACall() + // I considered whether we should try to reduce FPs from people passing file-like + // objects, which will not be a file system access (and couldn't cause a + // path-injection). + // + // I suppose that once we have proper flow-summary support for file-like objects, + // we can make the XXE/XML-bomb sinks allow an access-path, while the + // path-injection sink wouldn't, and then we will not end up with such FPs. + } + + override DataFlow::Node getAPathArgument() { result = this.getAnInput() } + } } // --------------------------------------------------------------------------- diff --git a/python/ql/test/library-tests/frameworks/stdlib/xml_dom.py b/python/ql/test/library-tests/frameworks/stdlib/xml_dom.py index c6152c75807..b3a1ab7f930 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/xml_dom.py +++ b/python/ql/test/library-tests/frameworks/stdlib/xml_dom.py @@ -6,16 +6,16 @@ import xml.sax x = "some xml" # minidom -xml.dom.minidom.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parse(..) -xml.dom.minidom.parse(file=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parse(..) +xml.dom.minidom.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) +xml.dom.minidom.parse(file=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) xml.dom.minidom.parseString(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parseString(..) xml.dom.minidom.parseString(string=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parseString(..) # pulldom -xml.dom.pulldom.parse(StringIO(x))['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parse(..) -xml.dom.pulldom.parse(stream_or_string=StringIO(x))['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parse(..) +xml.dom.pulldom.parse(StringIO(x))['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) +xml.dom.pulldom.parse(stream_or_string=StringIO(x))['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) xml.dom.pulldom.parseString(x)['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parseString(..) xml.dom.pulldom.parseString(string=x)['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parseString(..) @@ -24,8 +24,8 @@ xml.dom.pulldom.parseString(string=x)['START_DOCUMENT'][1] # $ decodeFormat=XML # These are based on SAX parses, and you can specify your own, so you can expose yourself to XXE (yay/) parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) -xml.dom.minidom.parse(StringIO(x), parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.minidom.parse(..) -xml.dom.minidom.parse(StringIO(x), parser=parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.minidom.parse(..) +xml.dom.minidom.parse(StringIO(x), parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) +xml.dom.minidom.parse(StringIO(x), parser=parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) -xml.dom.pulldom.parse(StringIO(x), parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.pulldom.parse(..) -xml.dom.pulldom.parse(StringIO(x), parser=parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.pulldom.parse(..) +xml.dom.pulldom.parse(StringIO(x), parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) +xml.dom.pulldom.parse(StringIO(x), parser=parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) diff --git a/python/ql/test/library-tests/frameworks/stdlib/xml_sax.py b/python/ql/test/library-tests/frameworks/stdlib/xml_sax.py index 8dbe9d4ae99..c08034907a4 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/xml_sax.py +++ b/python/ql/test/library-tests/frameworks/stdlib/xml_sax.py @@ -10,41 +10,41 @@ class MainHandler(xml.sax.ContentHandler): def characters(self, data): self._result.append(data) -xml.sax.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.sax.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.sax.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) +xml.sax.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) xml.sax.parseString(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' xml.sax.parseString(string=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' parser = xml.sax.make_parser() -parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -parser.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) +parser.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) # You can make it vuln to both XXE and DTD retrieval by setting this flag # see https://docs.python.org/3/library/xml.sax.handler.html#xml.sax.handler.feature_external_ges parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) -parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' getAPathArgument=StringIO(..) parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, False) -parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) # Forward Type Tracking test def func(cond): parser = xml.sax.make_parser() if cond: parser.setFeature(xml.sax.handler.feature_external_ges, True) - parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' getAPathArgument=StringIO(..) else: - parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) # make it vuln, then making it safe # a bit of an edge-case, but is nice to be able to handle. parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) parser.setFeature(xml.sax.handler.feature_external_ges, False) -parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) def check_conditional_assignment(cond): parser = xml.sax.make_parser() @@ -52,7 +52,7 @@ def check_conditional_assignment(cond): parser.setFeature(xml.sax.handler.feature_external_ges, True) else: parser.setFeature(xml.sax.handler.feature_external_ges, False) - parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' getAPathArgument=StringIO(..) def check_conditional_assignment2(cond): parser = xml.sax.make_parser() @@ -61,4 +61,4 @@ def check_conditional_assignment2(cond): else: flag_value = False parser.setFeature(xml.sax.handler.feature_external_ges, flag_value) - parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' getAPathArgument=StringIO(..) From 673220b231fdfcd225f4d29cbc76be67f156b21c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 18:18:35 +0200 Subject: [PATCH 073/171] Python: Minor cleanup of `XmlParsingTest` --- .../ql/test/experimental/meta/ConceptsTest.qll | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 24cbbab2d44..cd90d716dd4 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -543,18 +543,16 @@ class HttpClientRequestTest extends InlineExpectationsTest { class XmlParsingTest extends InlineExpectationsTest { XmlParsingTest() { this = "XmlParsingTest" } - override string getARelevantTag() { result in ["xmlInput", "xmlVuln"] } + override string getARelevantTag() { result in ["xmlVuln"] } override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and - exists(XML::XMLParsing parsing | - exists(XML::XMLParsingVulnerabilityKind kind | - parsing.vulnerableTo(kind) and - location = parsing.getLocation() and - element = parsing.toString() and - value = "'" + kind + "'" and - tag = "xmlVuln" - ) + exists(XML::XMLParsing parsing, XML::XMLParsingVulnerabilityKind kind | + parsing.vulnerableTo(kind) and + location = parsing.getLocation() and + element = parsing.toString() and + value = "'" + kind + "'" and + tag = "xmlVuln" ) } } From 5083023aa80238c58811aa7e56df6dddf4e6b33a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 18:37:47 +0200 Subject: [PATCH 074/171] Python: Move XML parsing PoC Since the folder where it used to live is now empty otherwise :O --- python/PoCs/README.md | 1 + .../library-tests/frameworks/XML/poc => PoCs/XmlParsing}/PoC.py | 0 .../library-tests/frameworks/XML/poc => PoCs/XmlParsing}/flag | 0 python/ql/lib/semmle/python/Concepts.qll | 2 ++ .../library-tests/frameworks/XML/poc/this-dir-is-not-extracted | 1 - 5 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 python/PoCs/README.md rename python/{ql/test/experimental/library-tests/frameworks/XML/poc => PoCs/XmlParsing}/PoC.py (100%) rename python/{ql/test/experimental/library-tests/frameworks/XML/poc => PoCs/XmlParsing}/flag (100%) delete mode 100644 python/ql/test/experimental/library-tests/frameworks/XML/poc/this-dir-is-not-extracted diff --git a/python/PoCs/README.md b/python/PoCs/README.md new file mode 100644 index 00000000000..20eeb5dbd78 --- /dev/null +++ b/python/PoCs/README.md @@ -0,0 +1 @@ +A place to collect proof of concept for how certain vulnerabilities work. diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py b/python/PoCs/XmlParsing/PoC.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/XML/poc/PoC.py rename to python/PoCs/XmlParsing/PoC.py diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/poc/flag b/python/PoCs/XmlParsing/flag similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/XML/poc/flag rename to python/PoCs/XmlParsing/flag diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index b553c8d927d..b1727e4829d 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -555,6 +555,8 @@ module XML { * A kind of XML vulnerability. * * See overview of kinds at https://pypi.org/project/defusedxml/#python-xml-libraries + * + * See PoC at `python/PoCs/XmlParsing/PoC.py` for some tests of vulnerable XML parsing. */ class XMLParsingVulnerabilityKind extends string { XMLParsingVulnerabilityKind() { diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/poc/this-dir-is-not-extracted b/python/ql/test/experimental/library-tests/frameworks/XML/poc/this-dir-is-not-extracted deleted file mode 100644 index b1925ade1d3..00000000000 --- a/python/ql/test/experimental/library-tests/frameworks/XML/poc/this-dir-is-not-extracted +++ /dev/null @@ -1 +0,0 @@ -just FYI From b8d3c5e96fbfc0b5770591d699b94695f3d15a26 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 18:40:26 +0200 Subject: [PATCH 075/171] Python: Remove last bits of experimental XML modeling --- python/ql/src/experimental/semmle/python/Frameworks.qll | 1 - .../ql/src/experimental/semmle/python/frameworks/Xml.qll | 9 --------- .../python/security/dataflow/XmlBombCustomizations.qll | 1 - .../python/security/dataflow/XxeCustomizations.qll | 1 - .../library-tests/frameworks/XML/ConceptsTest.expected | 0 .../library-tests/frameworks/XML/ConceptsTest.ql | 3 --- 6 files changed, 15 deletions(-) delete mode 100644 python/ql/src/experimental/semmle/python/frameworks/Xml.qll delete mode 100644 python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.expected delete mode 100644 python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.ql diff --git a/python/ql/src/experimental/semmle/python/Frameworks.qll b/python/ql/src/experimental/semmle/python/Frameworks.qll index edbed61c41c..81b2c1bee23 100644 --- a/python/ql/src/experimental/semmle/python/Frameworks.qll +++ b/python/ql/src/experimental/semmle/python/Frameworks.qll @@ -3,7 +3,6 @@ */ private import experimental.semmle.python.frameworks.Stdlib -private import experimental.semmle.python.frameworks.Xml private import experimental.semmle.python.frameworks.Flask private import experimental.semmle.python.frameworks.Django private import experimental.semmle.python.frameworks.Werkzeug diff --git a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll b/python/ql/src/experimental/semmle/python/frameworks/Xml.qll deleted file mode 100644 index 344a19a0109..00000000000 --- a/python/ql/src/experimental/semmle/python/frameworks/Xml.qll +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Provides class and predicates to track external data that - * may represent malicious XML objects. - */ - -private import python -private import semmle.python.dataflow.new.DataFlow -private import semmle.python.Concepts -private import semmle.python.ApiGraphs diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll index c5e69c1e0e3..d6f2e0791f9 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll @@ -7,7 +7,6 @@ private import python private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts -import experimental.semmle.python.frameworks.Xml // needed until modeling have been promoted private import semmle.python.dataflow.new.RemoteFlowSources /** diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll index 27d011625a6..a4473285b8d 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll @@ -7,7 +7,6 @@ private import python private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts -import experimental.semmle.python.frameworks.Xml // needed until modeling have been promoted private import semmle.python.dataflow.new.RemoteFlowSources /** diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.expected b/python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.expected deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.ql b/python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.ql deleted file mode 100644 index 95728bd6dc8..00000000000 --- a/python/ql/test/experimental/library-tests/frameworks/XML/ConceptsTest.ql +++ /dev/null @@ -1,3 +0,0 @@ -import python -import experimental.meta.ConceptsTest -import experimental.semmle.python.frameworks.Xml // needed until modeling have been promoted From 4abab2206618b950509b45ed516b8a9c11f7732d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 18:47:50 +0200 Subject: [PATCH 076/171] Python: Promote XXE and XML-bomb queries Need to write a change-note as well, but will do that tomorrow --- .../{experimental/Security/NEW => Security}/CWE-611/Xxe.qhelp | 0 .../src/{experimental/Security/NEW => Security}/CWE-611/Xxe.ql | 0 .../Security/NEW => Security}/CWE-611/examples/XxeBad.py | 0 .../Security/NEW => Security}/CWE-611/examples/XxeGood.py | 0 .../Security/NEW => Security}/CWE-776/XmlBomb.qhelp | 0 .../{experimental/Security/NEW => Security}/CWE-776/XmlBomb.ql | 0 .../Security/NEW => Security}/CWE-776/examples/XmlBombBad.py | 0 .../Security/NEW => Security}/CWE-776/examples/XmlBombGood.py | 0 .../test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.qlref | 1 - .../query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref | 1 - .../query-tests/Security/CWE-611-Xxe/Xxe.expected | 0 python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.qlref | 1 + .../{experimental => }/query-tests/Security/CWE-611-Xxe/test.py | 0 .../query-tests/Security/CWE-776-XmlBomb/XmlBomb.expected | 0 .../ql/test/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref | 1 + .../query-tests/Security/CWE-776-XmlBomb/test.py | 0 16 files changed, 2 insertions(+), 2 deletions(-) rename python/ql/src/{experimental/Security/NEW => Security}/CWE-611/Xxe.qhelp (100%) rename python/ql/src/{experimental/Security/NEW => Security}/CWE-611/Xxe.ql (100%) rename python/ql/src/{experimental/Security/NEW => Security}/CWE-611/examples/XxeBad.py (100%) rename python/ql/src/{experimental/Security/NEW => Security}/CWE-611/examples/XxeGood.py (100%) rename python/ql/src/{experimental/Security/NEW => Security}/CWE-776/XmlBomb.qhelp (100%) rename python/ql/src/{experimental/Security/NEW => Security}/CWE-776/XmlBomb.ql (100%) rename python/ql/src/{experimental/Security/NEW => Security}/CWE-776/examples/XmlBombBad.py (100%) rename python/ql/src/{experimental/Security/NEW => Security}/CWE-776/examples/XmlBombGood.py (100%) delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.qlref delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref rename python/ql/test/{experimental => }/query-tests/Security/CWE-611-Xxe/Xxe.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.qlref rename python/ql/test/{experimental => }/query-tests/Security/CWE-611-Xxe/test.py (100%) rename python/ql/test/{experimental => }/query-tests/Security/CWE-776-XmlBomb/XmlBomb.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref rename python/ql/test/{experimental => }/query-tests/Security/CWE-776-XmlBomb/test.py (100%) diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp b/python/ql/src/Security/CWE-611/Xxe.qhelp similarity index 100% rename from python/ql/src/experimental/Security/NEW/CWE-611/Xxe.qhelp rename to python/ql/src/Security/CWE-611/Xxe.qhelp diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/Xxe.ql b/python/ql/src/Security/CWE-611/Xxe.ql similarity index 100% rename from python/ql/src/experimental/Security/NEW/CWE-611/Xxe.ql rename to python/ql/src/Security/CWE-611/Xxe.ql diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeBad.py b/python/ql/src/Security/CWE-611/examples/XxeBad.py similarity index 100% rename from python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeBad.py rename to python/ql/src/Security/CWE-611/examples/XxeBad.py diff --git a/python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.py b/python/ql/src/Security/CWE-611/examples/XxeGood.py similarity index 100% rename from python/ql/src/experimental/Security/NEW/CWE-611/examples/XxeGood.py rename to python/ql/src/Security/CWE-611/examples/XxeGood.py diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.qhelp b/python/ql/src/Security/CWE-776/XmlBomb.qhelp similarity index 100% rename from python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.qhelp rename to python/ql/src/Security/CWE-776/XmlBomb.qhelp diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.ql b/python/ql/src/Security/CWE-776/XmlBomb.ql similarity index 100% rename from python/ql/src/experimental/Security/NEW/CWE-776/XmlBomb.ql rename to python/ql/src/Security/CWE-776/XmlBomb.ql diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombBad.py b/python/ql/src/Security/CWE-776/examples/XmlBombBad.py similarity index 100% rename from python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombBad.py rename to python/ql/src/Security/CWE-776/examples/XmlBombBad.py diff --git a/python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.py b/python/ql/src/Security/CWE-776/examples/XmlBombGood.py similarity index 100% rename from python/ql/src/experimental/Security/NEW/CWE-776/examples/XmlBombGood.py rename to python/ql/src/Security/CWE-776/examples/XmlBombGood.py diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.qlref b/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.qlref deleted file mode 100644 index f8a07d7d2ee..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/NEW/CWE-611/Xxe.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref b/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref deleted file mode 100644 index 5eadbb1f26f..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/NEW/CWE-776/XmlBomb.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.expected b/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.expected similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/Xxe.expected rename to python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.expected diff --git a/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.qlref b/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.qlref new file mode 100644 index 00000000000..62a3f7f22d9 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.qlref @@ -0,0 +1 @@ +Security/CWE-611/Xxe.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/test.py b/python/ql/test/query-tests/Security/CWE-611-Xxe/test.py similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-611-Xxe/test.py rename to python/ql/test/query-tests/Security/CWE-611-Xxe/test.py diff --git a/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.expected b/python/ql/test/query-tests/Security/CWE-776-XmlBomb/XmlBomb.expected similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/XmlBomb.expected rename to python/ql/test/query-tests/Security/CWE-776-XmlBomb/XmlBomb.expected diff --git a/python/ql/test/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref b/python/ql/test/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref new file mode 100644 index 00000000000..c983b357446 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-776-XmlBomb/XmlBomb.qlref @@ -0,0 +1 @@ +Security/CWE-776/XmlBomb.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/test.py b/python/ql/test/query-tests/Security/CWE-776-XmlBomb/test.py similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-776-XmlBomb/test.py rename to python/ql/test/query-tests/Security/CWE-776-XmlBomb/test.py From d2b03bb4809b1156d1d0799ca739da4265c68ba7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 31 Mar 2022 20:37:28 +0200 Subject: [PATCH 077/171] Python: Fix `SimpleXmlRpcServer.ql` --- .../src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql b/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql index 3d2a736ed49..53ff6eeedb8 100644 --- a/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql +++ b/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql @@ -10,14 +10,14 @@ */ private import python -private import experimental.semmle.python.Concepts +private import semmle.python.Concepts private import semmle.python.ApiGraphs from DataFlow::CallCfgNode call, string kinds where call = API::moduleImport("xmlrpc").getMember("server").getMember("SimpleXMLRPCServer").getACall() and kinds = - strictconcat(ExperimentalXML::XMLParsingVulnerabilityKind kind | + strictconcat(XML::XMLParsingVulnerabilityKind kind | kind.isBillionLaughs() or kind.isQuadraticBlowup() | kind, ", " From ab59d5c786893d71dc044107af0517e56b460171 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 Apr 2022 11:06:22 +0200 Subject: [PATCH 078/171] Python: Rename to `XmlParsing` To follow our style guide --- python/ql/lib/semmle/python/Concepts.qll | 8 ++++---- python/ql/lib/semmle/python/frameworks/Lxml.qll | 6 +++--- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 10 +++++----- python/ql/lib/semmle/python/frameworks/Xmltodict.qll | 2 +- .../python/security/dataflow/XmlBombCustomizations.qll | 2 +- .../python/security/dataflow/XxeCustomizations.qll | 2 +- python/ql/test/experimental/meta/ConceptsTest.qll | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index b1727e4829d..b0a5e1766a2 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -580,9 +580,9 @@ module XML { * A data-flow node that parses XML. * * Extend this class to model new APIs. If you want to refine existing API models, - * extend `XMLParsing` instead. + * extend `XmlParsing` instead. */ - class XMLParsing extends Decoding instanceof XMLParsing::Range { + class XmlParsing extends Decoding instanceof XmlParsing::Range { /** * Holds if this XML parsing is vulnerable to `kind`. */ @@ -590,12 +590,12 @@ module XML { } /** Provides classes for modeling XML parsing APIs. */ - module XMLParsing { + module XmlParsing { /** * A data-flow node that parses XML. * * Extend this class to model new APIs. If you want to refine existing API models, - * extend `XMLParsing` instead. + * extend `XmlParsing` instead. */ abstract class Range extends Decoding::Range { /** diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index a3825a70db0..05dfd388dac 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -196,7 +196,7 @@ private module Lxml { /** * A call to the `feed` method of an `lxml` parser. */ - private class LXMLParserFeedCall extends DataFlow::MethodCallNode, XML::XMLParsing::Range { + private class LXMLParserFeedCall extends DataFlow::MethodCallNode, XML::XmlParsing::Range { LXMLParserFeedCall() { this.calls(instance(_), "feed") } override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } @@ -233,7 +233,7 @@ private module Lxml { * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parse * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parseid */ - private class LXMLParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { + private class LXMLParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { LXMLParsing() { this = API::moduleImport("lxml") @@ -305,7 +305,7 @@ private module Lxml { * See * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.iterparse */ - private class LXMLIterparseCall extends DataFlow::CallCfgNode, XML::XMLParsing::Range, + private class LXMLIterparseCall extends DataFlow::CallCfgNode, XML::XmlParsing::Range, FileSystemAccess::Range { LXMLIterparseCall() { this = API::moduleImport("lxml").getMember("etree").getMember("iterparse").getACall() diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 38fe32a3b3c..e45e8e3a879 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3236,7 +3236,7 @@ private module StdlibPrivate { /** * A call to the `feed` method of an `xml.etree` parser. */ - private class XMLEtreeParserFeedCall extends DataFlow::MethodCallNode, XML::XMLParsing::Range { + private class XMLEtreeParserFeedCall extends DataFlow::MethodCallNode, XML::XmlParsing::Range { XMLEtreeParserFeedCall() { this.calls(instance(), "feed") } override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } @@ -3274,7 +3274,7 @@ private module StdlibPrivate { * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.parse * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.iterparse */ - private class XMLEtreeParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { + private class XMLEtreeParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { XMLEtreeParsing() { this = API::moduleImport("xml") @@ -3445,7 +3445,7 @@ private module StdlibPrivate { * * See https://docs.python.org/3/library/xml.sax.reader.html#xml.sax.xmlreader.XMLReader.parse */ - private class XMLSaxInstanceParsing extends DataFlow::MethodCallNode, XML::XMLParsing::Range, + private class XMLSaxInstanceParsing extends DataFlow::MethodCallNode, XML::XmlParsing::Range, FileSystemAccess::Range { XMLSaxInstanceParsing() { this = @@ -3496,7 +3496,7 @@ private module StdlibPrivate { * - https://docs.python.org/3.10/library/xml.sax.html#xml.sax.parse * - https://docs.python.org/3.10/library/xml.sax.html#xml.sax.parseString */ - private class XMLSaxParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { + private class XMLSaxParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { XMLSaxParsing() { this = API::moduleImport("xml").getMember("sax").getMember(["parse", "parseString"]).getACall() @@ -3562,7 +3562,7 @@ private module StdlibPrivate { * - https://docs.python.org/3/library/xml.dom.minidom.html#xml.dom.minidom.parse * - https://docs.python.org/3/library/xml.dom.pulldom.html#xml.dom.pulldom.parse */ - private class XMLDomParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { + private class XMLDomParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { XMLDomParsing() { this = API::moduleImport("xml") diff --git a/python/ql/lib/semmle/python/frameworks/Xmltodict.qll b/python/ql/lib/semmle/python/frameworks/Xmltodict.qll index bb65607251f..84b0b0fe03f 100644 --- a/python/ql/lib/semmle/python/frameworks/Xmltodict.qll +++ b/python/ql/lib/semmle/python/frameworks/Xmltodict.qll @@ -20,7 +20,7 @@ private module Xmltodict { /** * A call to `xmltodict.parse`. */ - private class XMLtoDictParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range { + private class XMLtoDictParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { XMLtoDictParsing() { this = API::moduleImport("xmltodict").getMember("parse").getACall() } override DataFlow::Node getAnInput() { diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll index d6f2e0791f9..5da602173a1 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll @@ -40,7 +40,7 @@ module XmlBomb { */ class XmlParsingWithEntityResolution extends Sink { XmlParsingWithEntityResolution() { - exists(XML::XMLParsing parsing, XML::XMLParsingVulnerabilityKind kind | + exists(XML::XmlParsing parsing, XML::XMLParsingVulnerabilityKind kind | (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and parsing.vulnerableTo(kind) and this = parsing.getAnInput() diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll index a4473285b8d..355b3aeefc9 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll @@ -40,7 +40,7 @@ module Xxe { */ class XmlParsingWithExternalEntityResolution extends Sink { XmlParsingWithExternalEntityResolution() { - exists(XML::XMLParsing parsing, XML::XMLParsingVulnerabilityKind kind | + exists(XML::XmlParsing parsing, XML::XMLParsingVulnerabilityKind kind | kind.isXxe() and parsing.vulnerableTo(kind) and this = parsing.getAnInput() diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index cd90d716dd4..24c3c270413 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -547,7 +547,7 @@ class XmlParsingTest extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and - exists(XML::XMLParsing parsing, XML::XMLParsingVulnerabilityKind kind | + exists(XML::XmlParsing parsing, XML::XMLParsingVulnerabilityKind kind | parsing.vulnerableTo(kind) and location = parsing.getLocation() and element = parsing.toString() and From 1f285b8983c15e31b08886aa4080f4fad3c8b42b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 Apr 2022 11:07:12 +0200 Subject: [PATCH 079/171] Python: Rename to `XmlParsingVulnerabilityKind` To keep up with style guide --- python/ql/lib/semmle/python/Concepts.qll | 8 ++++---- python/ql/lib/semmle/python/frameworks/Lxml.qll | 14 +++++++------- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 10 +++++----- .../ql/lib/semmle/python/frameworks/Xmltodict.qll | 2 +- .../Security/CWE-611/SimpleXmlRpcServer.ql | 2 +- .../security/dataflow/XmlBombCustomizations.qll | 2 +- .../python/security/dataflow/XxeCustomizations.qll | 2 +- python/ql/test/experimental/meta/ConceptsTest.qll | 2 +- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index b0a5e1766a2..091ce31a157 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -558,8 +558,8 @@ module XML { * * See PoC at `python/PoCs/XmlParsing/PoC.py` for some tests of vulnerable XML parsing. */ - class XMLParsingVulnerabilityKind extends string { - XMLParsingVulnerabilityKind() { + class XmlParsingVulnerabilityKind extends string { + XmlParsingVulnerabilityKind() { this in ["Billion Laughs", "Quadratic Blowup", "XXE", "DTD retrieval"] } @@ -586,7 +586,7 @@ module XML { /** * Holds if this XML parsing is vulnerable to `kind`. */ - predicate vulnerableTo(XMLParsingVulnerabilityKind kind) { super.vulnerableTo(kind) } + predicate vulnerableTo(XmlParsingVulnerabilityKind kind) { super.vulnerableTo(kind) } } /** Provides classes for modeling XML parsing APIs. */ @@ -601,7 +601,7 @@ module XML { /** * Holds if this XML parsing is vulnerable to `kind`. */ - abstract predicate vulnerableTo(XMLParsingVulnerabilityKind kind); + abstract predicate vulnerableTo(XmlParsingVulnerabilityKind kind); override string getFormat() { result = "XML" } } diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index 05dfd388dac..6d310563ade 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -121,7 +121,7 @@ private module Lxml { */ abstract class InstanceSource extends DataFlow::LocalSourceNode { /** Holds if this instance is vulnerable to `kind`. */ - abstract predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind); + abstract predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind); } /** @@ -135,7 +135,7 @@ private module Lxml { } // NOTE: it's not possible to change settings of a parser after constructing it - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { kind.isXxe() and ( // resolve_entities has default True @@ -165,7 +165,7 @@ private module Lxml { API::moduleImport("lxml").getMember("etree").getMember("get_default_parser").getACall() } - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { // as highlighted by // https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.XMLParser // by default XXE is allow. so as long as the default parser has not been @@ -189,7 +189,7 @@ private module Lxml { } /** Gets a reference to an `lxml.etree` parser instance, that is vulnerable to `kind`. */ - DataFlow::Node instanceVulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + DataFlow::Node instanceVulnerableTo(XML::XmlParsingVulnerabilityKind kind) { exists(InstanceSource origin | result = instance(origin) and origin.vulnerableTo(kind)) } @@ -201,7 +201,7 @@ private module Lxml { override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { this.calls(instanceVulnerableTo(kind), "feed") } @@ -256,7 +256,7 @@ private module Lxml { DataFlow::Node getParserArg() { result in [this.getArg(1), this.getArgByName("parser")] } - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { this.getParserArg() = XMLParser::instanceVulnerableTo(kind) or kind.isXxe() and @@ -313,7 +313,7 @@ private module Lxml { override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("source")] } - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { // note that there is no `resolve_entities` argument, so it's not possible to turn off XXE :O kind.isXxe() or diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index e45e8e3a879..91ba7bc75b5 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3241,7 +3241,7 @@ private module StdlibPrivate { override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { kind.isBillionLaughs() or kind.isQuadraticBlowup() } @@ -3298,7 +3298,7 @@ private module StdlibPrivate { ] } - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { // note: it does not matter what `xml.etree` parser you are using, you cannot // change the security features anyway :| kind.isBillionLaughs() or kind.isQuadraticBlowup() @@ -3459,7 +3459,7 @@ private module StdlibPrivate { override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("source")] } - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { // always vuln to these (kind.isBillionLaughs() or kind.isQuadraticBlowup()) or @@ -3512,7 +3512,7 @@ private module StdlibPrivate { ] } - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { // always vuln to these (kind.isBillionLaughs() or kind.isQuadraticBlowup()) } @@ -3586,7 +3586,7 @@ private module StdlibPrivate { DataFlow::Node getParserArg() { result in [this.getArg(1), this.getArgByName("parser")] } - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { this.getParserArg() = saxParserWithFeatureExternalGesTurnedOn() and (kind.isXxe() or kind.isDtdRetrieval()) or diff --git a/python/ql/lib/semmle/python/frameworks/Xmltodict.qll b/python/ql/lib/semmle/python/frameworks/Xmltodict.qll index 84b0b0fe03f..db2c443d8e9 100644 --- a/python/ql/lib/semmle/python/frameworks/Xmltodict.qll +++ b/python/ql/lib/semmle/python/frameworks/Xmltodict.qll @@ -27,7 +27,7 @@ private module Xmltodict { result in [this.getArg(0), this.getArgByName("xml_input")] } - override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) { + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and this.getArgByName("disable_entities").getALocalSource().asExpr() = any(False f) } diff --git a/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql b/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql index 53ff6eeedb8..e638c13853f 100644 --- a/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql +++ b/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql @@ -17,7 +17,7 @@ from DataFlow::CallCfgNode call, string kinds where call = API::moduleImport("xmlrpc").getMember("server").getMember("SimpleXMLRPCServer").getACall() and kinds = - strictconcat(XML::XMLParsingVulnerabilityKind kind | + strictconcat(XML::XmlParsingVulnerabilityKind kind | kind.isBillionLaughs() or kind.isQuadraticBlowup() | kind, ", " diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll index 5da602173a1..05f6fc57a34 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll @@ -40,7 +40,7 @@ module XmlBomb { */ class XmlParsingWithEntityResolution extends Sink { XmlParsingWithEntityResolution() { - exists(XML::XmlParsing parsing, XML::XMLParsingVulnerabilityKind kind | + exists(XML::XmlParsing parsing, XML::XmlParsingVulnerabilityKind kind | (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and parsing.vulnerableTo(kind) and this = parsing.getAnInput() diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll index 355b3aeefc9..0fc139ec4f3 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll @@ -40,7 +40,7 @@ module Xxe { */ class XmlParsingWithExternalEntityResolution extends Sink { XmlParsingWithExternalEntityResolution() { - exists(XML::XmlParsing parsing, XML::XMLParsingVulnerabilityKind kind | + exists(XML::XmlParsing parsing, XML::XmlParsingVulnerabilityKind kind | kind.isXxe() and parsing.vulnerableTo(kind) and this = parsing.getAnInput() diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 24c3c270413..73bcf8b4aa9 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -547,7 +547,7 @@ class XmlParsingTest extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and - exists(XML::XmlParsing parsing, XML::XMLParsingVulnerabilityKind kind | + exists(XML::XmlParsing parsing, XML::XmlParsingVulnerabilityKind kind | parsing.vulnerableTo(kind) and location = parsing.getLocation() and element = parsing.toString() and From a7dab53ed2df129e7bdab97cd04f73b9b133574b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 Apr 2022 11:46:49 +0200 Subject: [PATCH 080/171] Python: Add change-note --- python/ql/src/change-notes/2022-04-05-add-xxe-and-xmlbomb.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 python/ql/src/change-notes/2022-04-05-add-xxe-and-xmlbomb.md diff --git a/python/ql/src/change-notes/2022-04-05-add-xxe-and-xmlbomb.md b/python/ql/src/change-notes/2022-04-05-add-xxe-and-xmlbomb.md new file mode 100644 index 00000000000..bd867091aea --- /dev/null +++ b/python/ql/src/change-notes/2022-04-05-add-xxe-and-xmlbomb.md @@ -0,0 +1,5 @@ +--- +category: newQuery +--- +* "XML external entity expansion" (`py/xxe`). Results will appear by default. This query was based on [an experimental query by @jorgectf](https://github.com/github/codeql/pull/6112). +* "XML internal entity expansion" (`py/xml-bomb`). Results will appear by default. This query was based on [an experimental query by @jorgectf](https://github.com/github/codeql/pull/6112). From b7f56dd17e982ddace861a561ba851e8e7cf7e5c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 Apr 2022 12:31:09 +0200 Subject: [PATCH 081/171] Python: Rewrite concepts to use `extends ... instanceof ...` This caused compilation time for `ConceptsTest.ql` to go from 1m24s to 7s --- python/ql/lib/semmle/python/Concepts.qll | 241 ++++++++--------------- 1 file changed, 77 insertions(+), 164 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 091ce31a157..eec0cd0d1a0 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -17,13 +17,9 @@ private import semmle.python.Frameworks * Extend this class to refine existing API models. If you want to model new APIs, * extend `SystemCommandExecution::Range` instead. */ -class SystemCommandExecution extends DataFlow::Node { - SystemCommandExecution::Range range; - - SystemCommandExecution() { this = range } - +class SystemCommandExecution extends DataFlow::Node instanceof SystemCommandExecution::Range { /** Gets the argument that specifies the command to be executed. */ - DataFlow::Node getCommand() { result = range.getCommand() } + DataFlow::Node getCommand() { result = super.getCommand() } } /** Provides a class for modeling new system-command execution APIs. */ @@ -48,13 +44,9 @@ module SystemCommandExecution { * Extend this class to refine existing API models. If you want to model new APIs, * extend `FileSystemAccess::Range` instead. */ -class FileSystemAccess extends DataFlow::Node { - FileSystemAccess::Range range; - - FileSystemAccess() { this = range } - +class FileSystemAccess extends DataFlow::Node instanceof FileSystemAccess::Range { /** Gets an argument to this file system access that is interpreted as a path. */ - DataFlow::Node getAPathArgument() { result = range.getAPathArgument() } + DataFlow::Node getAPathArgument() { result = super.getAPathArgument() } } /** Provides a class for modeling new file system access APIs. */ @@ -78,14 +70,12 @@ module FileSystemAccess { * Extend this class to refine existing API models. If you want to model new APIs, * extend `FileSystemWriteAccess::Range` instead. */ -class FileSystemWriteAccess extends FileSystemAccess { - override FileSystemWriteAccess::Range range; - +class FileSystemWriteAccess extends FileSystemAccess instanceof FileSystemWriteAccess::Range { /** * Gets a node that represents data to be written to the file system (possibly with * some transformation happening before it is written, like JSON encoding). */ - DataFlow::Node getADataNode() { result = range.getADataNode() } + DataFlow::Node getADataNode() { result = super.getADataNode() } } /** Provides a class for modeling new file system writes. */ @@ -111,13 +101,9 @@ module Path { * A data-flow node that performs path normalization. This is often needed in order * to safely access paths. */ - class PathNormalization extends DataFlow::Node { - PathNormalization::Range range; - - PathNormalization() { this = range } - + class PathNormalization extends DataFlow::Node instanceof PathNormalization::Range { /** Gets an argument to this path normalization that is interpreted as a path. */ - DataFlow::Node getPathArg() { result = range.getPathArg() } + DataFlow::Node getPathArg() { result = super.getPathArg() } } /** Provides a class for modeling new path normalization APIs. */ @@ -133,12 +119,10 @@ module Path { } /** A data-flow node that checks that a path is safe to access. */ - class SafeAccessCheck extends DataFlow::BarrierGuard { - SafeAccessCheck::Range range; - - SafeAccessCheck() { this = range } - - override predicate checks(ControlFlowNode node, boolean branch) { range.checks(node, branch) } + class SafeAccessCheck extends DataFlow::BarrierGuard instanceof SafeAccessCheck::Range { + override predicate checks(ControlFlowNode node, boolean branch) { + SafeAccessCheck::Range.super.checks(node, branch) + } } /** Provides a class for modeling new path safety checks. */ @@ -160,22 +144,18 @@ module Path { * Extend this class to refine existing API models. If you want to model new APIs, * extend `Decoding::Range` instead. */ -class Decoding extends DataFlow::Node { - Decoding::Range range; - - Decoding() { this = range } - +class Decoding extends DataFlow::Node instanceof Decoding::Range { /** Holds if this call may execute code embedded in its input. */ - predicate mayExecuteInput() { range.mayExecuteInput() } + predicate mayExecuteInput() { super.mayExecuteInput() } /** Gets an input that is decoded by this function. */ - DataFlow::Node getAnInput() { result = range.getAnInput() } + DataFlow::Node getAnInput() { result = super.getAnInput() } /** Gets the output that contains the decoded data produced by this function. */ - DataFlow::Node getOutput() { result = range.getOutput() } + DataFlow::Node getOutput() { result = super.getOutput() } /** Gets an identifier for the format this function decodes from, such as "JSON". */ - string getFormat() { result = range.getFormat() } + string getFormat() { result = super.getFormat() } } /** Provides a class for modeling new decoding mechanisms. */ @@ -226,19 +206,15 @@ private class DecodingAdditionalTaintStep extends TaintTracking::AdditionalTaint * Extend this class to refine existing API models. If you want to model new APIs, * extend `Encoding::Range` instead. */ -class Encoding extends DataFlow::Node { - Encoding::Range range; - - Encoding() { this = range } - +class Encoding extends DataFlow::Node instanceof Encoding::Range { /** Gets an input that is encoded by this function. */ - DataFlow::Node getAnInput() { result = range.getAnInput() } + DataFlow::Node getAnInput() { result = super.getAnInput() } /** Gets the output that contains the encoded data produced by this function. */ - DataFlow::Node getOutput() { result = range.getOutput() } + DataFlow::Node getOutput() { result = super.getOutput() } /** Gets an identifier for the format this function decodes from, such as "JSON". */ - string getFormat() { result = range.getFormat() } + string getFormat() { result = super.getFormat() } } /** Provides a class for modeling new encoding mechanisms. */ @@ -280,13 +256,9 @@ private class EncodingAdditionalTaintStep extends TaintTracking::AdditionalTaint * Extend this class to refine existing API models. If you want to model new APIs, * extend `Logging::Range` instead. */ -class Logging extends DataFlow::Node { - Logging::Range range; - - Logging() { this = range } - +class Logging extends DataFlow::Node instanceof Logging::Range { /** Gets an input that is logged. */ - DataFlow::Node getAnInput() { result = range.getAnInput() } + DataFlow::Node getAnInput() { result = super.getAnInput() } } /** Provides a class for modeling new logging mechanisms. */ @@ -309,13 +281,9 @@ module Logging { * Extend this class to refine existing API models. If you want to model new APIs, * extend `CodeExecution::Range` instead. */ -class CodeExecution extends DataFlow::Node { - CodeExecution::Range range; - - CodeExecution() { this = range } - +class CodeExecution extends DataFlow::Node instanceof CodeExecution::Range { /** Gets the argument that specifies the code to be executed. */ - DataFlow::Node getCode() { result = range.getCode() } + DataFlow::Node getCode() { result = super.getCode() } } /** Provides a class for modeling new dynamic code execution APIs. */ @@ -343,13 +311,9 @@ module CodeExecution { * Extend this class to refine existing API models. If you want to model new APIs, * extend `SqlConstruction::Range` instead. */ -class SqlConstruction extends DataFlow::Node { - SqlConstruction::Range range; - - SqlConstruction() { this = range } - +class SqlConstruction extends DataFlow::Node instanceof SqlConstruction::Range { /** Gets the argument that specifies the SQL statements to be constructed. */ - DataFlow::Node getSql() { result = range.getSql() } + DataFlow::Node getSql() { result = super.getSql() } } /** Provides a class for modeling new SQL execution APIs. */ @@ -380,13 +344,9 @@ module SqlConstruction { * Extend this class to refine existing API models. If you want to model new APIs, * extend `SqlExecution::Range` instead. */ -class SqlExecution extends DataFlow::Node { - SqlExecution::Range range; - - SqlExecution() { this = range } - +class SqlExecution extends DataFlow::Node instanceof SqlExecution::Range { /** Gets the argument that specifies the SQL statements to be executed. */ - DataFlow::Node getSql() { result = range.getSql() } + DataFlow::Node getSql() { result = super.getSql() } } /** Provides a class for modeling new SQL execution APIs. */ @@ -412,22 +372,18 @@ module SqlExecution { * Extend this class to refine existing API models. If you want to model new APIs, * extend `RegexExecution::Range` instead. */ -class RegexExecution extends DataFlow::Node { - RegexExecution::Range range; - - RegexExecution() { this = range } - +class RegexExecution extends DataFlow::Node instanceof RegexExecution::Range { /** Gets the data flow node for the regex being executed by this node. */ - DataFlow::Node getRegex() { result = range.getRegex() } + DataFlow::Node getRegex() { result = super.getRegex() } /** Gets a dataflow node for the string to be searched or matched against. */ - DataFlow::Node getString() { result = range.getString() } + DataFlow::Node getString() { result = super.getString() } /** * Gets the name of this regex execution, typically the name of an executing method. * This is used for nice alert messages and should include the module if possible. */ - string getName() { result = range.getName() } + string getName() { result = super.getName() } } /** Provides classes for modeling new regular-expression execution APIs. */ @@ -466,19 +422,15 @@ module XML { * Extend this class to refine existing API models. If you want to model new APIs, * extend `XPathConstruction::Range` instead. */ - class XPathConstruction extends DataFlow::Node { - XPathConstruction::Range range; - - XPathConstruction() { this = range } - + class XPathConstruction extends DataFlow::Node instanceof XPathConstruction::Range { /** Gets the argument that specifies the XPath expressions to be constructed. */ - DataFlow::Node getXPath() { result = range.getXPath() } + DataFlow::Node getXPath() { result = super.getXPath() } /** * Gets the name of this XPath expression construction, typically the name of an executing method. * This is used for nice alert messages and should include the module if possible. */ - string getName() { result = range.getName() } + string getName() { result = super.getName() } } /** Provides a class for modeling new XPath construction APIs. */ @@ -513,19 +465,15 @@ module XML { * Extend this class to refine existing API models. If you want to model new APIs, * extend `XPathExecution::Range` instead. */ - class XPathExecution extends DataFlow::Node { - XPathExecution::Range range; - - XPathExecution() { this = range } - + class XPathExecution extends DataFlow::Node instanceof XPathExecution::Range { /** Gets the data flow node for the XPath expression being executed by this node. */ - DataFlow::Node getXPath() { result = range.getXPath() } + DataFlow::Node getXPath() { result = super.getXPath() } /** * Gets the name of this XPath expression execution, typically the name of an executing method. * This is used for nice alert messages and should include the module if possible. */ - string getName() { result = range.getName() } + string getName() { result = super.getName() } } /** Provides classes for modeling new regular-expression execution APIs. */ @@ -616,16 +564,12 @@ module LDAP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `LDAPQuery::Range` instead. */ - class LdapExecution extends DataFlow::Node { - LdapExecution::Range range; - - LdapExecution() { this = range } - + class LdapExecution extends DataFlow::Node instanceof LdapExecution::Range { /** Gets the argument containing the filter string. */ - DataFlow::Node getFilter() { result = range.getFilter() } + DataFlow::Node getFilter() { result = super.getFilter() } /** Gets the argument containing the base DN. */ - DataFlow::Node getBaseDn() { result = range.getBaseDn() } + DataFlow::Node getBaseDn() { result = super.getBaseDn() } } /** Provides classes for modeling new LDAP query execution-related APIs. */ @@ -653,26 +597,23 @@ module LDAP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `Escaping::Range` instead. */ -class Escaping extends DataFlow::Node { - Escaping::Range range; - +class Escaping extends DataFlow::Node instanceof Escaping::Range { Escaping() { - this = range and // escapes that don't have _both_ input/output defined are not valid - exists(range.getAnInput()) and - exists(range.getOutput()) + exists(super.getAnInput()) and + exists(super.getOutput()) } /** Gets an input that will be escaped. */ - DataFlow::Node getAnInput() { result = range.getAnInput() } + DataFlow::Node getAnInput() { result = super.getAnInput() } /** Gets the output that contains the escaped data. */ - DataFlow::Node getOutput() { result = range.getOutput() } + DataFlow::Node getOutput() { result = super.getOutput() } /** * Gets the context that this function escapes for, such as `html`, or `url`. */ - string getKind() { result = range.getKind() } + string getKind() { result = super.getKind() } } /** Provides a class for modeling new escaping APIs. */ @@ -730,7 +671,7 @@ module Escaping { * `

    {}

    `. */ class HtmlEscaping extends Escaping { - HtmlEscaping() { range.getKind() = Escaping::getHtmlKind() } + HtmlEscaping() { super.getKind() = Escaping::getHtmlKind() } } /** @@ -738,7 +679,7 @@ class HtmlEscaping extends Escaping { * the body of a regex. */ class RegexEscaping extends Escaping { - RegexEscaping() { range.getKind() = Escaping::getRegexKind() } + RegexEscaping() { super.getKind() = Escaping::getRegexKind() } } /** @@ -746,14 +687,14 @@ class RegexEscaping extends Escaping { * in an LDAP search. */ class LdapDnEscaping extends Escaping { - LdapDnEscaping() { range.getKind() = Escaping::getLdapDnKind() } + LdapDnEscaping() { super.getKind() = Escaping::getLdapDnKind() } } /** * An escape of a string so it can be safely used as a filter in an LDAP search. */ class LdapFilterEscaping extends Escaping { - LdapFilterEscaping() { range.getKind() = Escaping::getLdapFilterKind() } + LdapFilterEscaping() { super.getKind() = Escaping::getLdapFilterKind() } } /** Provides classes for modeling HTTP-related APIs. */ @@ -772,29 +713,25 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `RouteSetup::Range` instead. */ - class RouteSetup extends DataFlow::Node { - RouteSetup::Range range; - - RouteSetup() { this = range } - + class RouteSetup extends DataFlow::Node instanceof RouteSetup::Range { /** Gets the URL pattern for this route, if it can be statically determined. */ - string getUrlPattern() { result = range.getUrlPattern() } + string getUrlPattern() { result = super.getUrlPattern() } /** * Gets a function that will handle incoming requests for this route, if any. * * NOTE: This will be modified in the near future to have a `RequestHandler` result, instead of a `Function`. */ - Function getARequestHandler() { result = range.getARequestHandler() } + Function getARequestHandler() { result = super.getARequestHandler() } /** * Gets a parameter that will receive parts of the url when handling incoming * requests for this route, if any. These automatically become a `RemoteFlowSource`. */ - Parameter getARoutedParameter() { result = range.getARoutedParameter() } + Parameter getARoutedParameter() { result = super.getARoutedParameter() } /** Gets a string that identifies the framework used for this route setup. */ - string getFramework() { result = range.getFramework() } + string getFramework() { result = super.getFramework() } } /** Provides a class for modeling new HTTP routing APIs. */ @@ -841,19 +778,15 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `RequestHandler::Range` instead. */ - class RequestHandler extends Function { - RequestHandler::Range range; - - RequestHandler() { this = range } - + class RequestHandler extends Function instanceof RequestHandler::Range { /** * Gets a parameter that could receive parts of the url when handling incoming * requests, if any. These automatically become a `RemoteFlowSource`. */ - Parameter getARoutedParameter() { result = range.getARoutedParameter() } + Parameter getARoutedParameter() { result = super.getARoutedParameter() } /** Gets a string that identifies the framework used for this route setup. */ - string getFramework() { result = range.getFramework() } + string getFramework() { result = super.getFramework() } } /** Provides a class for modeling new HTTP request handlers. */ @@ -909,16 +842,12 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `HttpResponse::Range` instead. */ - class HttpResponse extends DataFlow::Node { - HttpResponse::Range range; - - HttpResponse() { this = range } - + class HttpResponse extends DataFlow::Node instanceof HttpResponse::Range { /** Gets the data-flow node that specifies the body of this HTTP response. */ - DataFlow::Node getBody() { result = range.getBody() } + DataFlow::Node getBody() { result = super.getBody() } /** Gets the mimetype of this HTTP response, if it can be statically determined. */ - string getMimetype() { result = range.getMimetype() } + string getMimetype() { result = super.getMimetype() } } /** Provides a class for modeling new HTTP response APIs. */ @@ -964,13 +893,9 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `HttpRedirectResponse::Range` instead. */ - class HttpRedirectResponse extends HttpResponse { - override HttpRedirectResponse::Range range; - - HttpRedirectResponse() { this = range } - + class HttpRedirectResponse extends HttpResponse instanceof HttpRedirectResponse::Range { /** Gets the data-flow node that specifies the location of this HTTP redirect response. */ - DataFlow::Node getRedirectLocation() { result = range.getRedirectLocation() } + DataFlow::Node getRedirectLocation() { result = super.getRedirectLocation() } } /** Provides a class for modeling new HTTP redirect response APIs. */ @@ -996,25 +921,21 @@ module HTTP { * Extend this class to refine existing API models. If you want to model new APIs, * extend `HTTP::CookieWrite::Range` instead. */ - class CookieWrite extends DataFlow::Node { - CookieWrite::Range range; - - CookieWrite() { this = range } - + class CookieWrite extends DataFlow::Node instanceof CookieWrite::Range { /** * Gets the argument, if any, specifying the raw cookie header. */ - DataFlow::Node getHeaderArg() { result = range.getHeaderArg() } + DataFlow::Node getHeaderArg() { result = super.getHeaderArg() } /** * Gets the argument, if any, specifying the cookie name. */ - DataFlow::Node getNameArg() { result = range.getNameArg() } + DataFlow::Node getNameArg() { result = super.getNameArg() } /** * Gets the argument, if any, specifying the cookie value. */ - DataFlow::Node getValueArg() { result = range.getValueArg() } + DataFlow::Node getValueArg() { result = super.getValueArg() } } /** Provides a class for modeling new cookie writes on HTTP responses. */ @@ -1131,27 +1052,23 @@ module Cryptography { * Extend this class to refine existing API models. If you want to model new APIs, * extend `KeyGeneration::Range` instead. */ - class KeyGeneration extends DataFlow::Node { - KeyGeneration::Range range; - - KeyGeneration() { this = range } - + class KeyGeneration extends DataFlow::Node instanceof KeyGeneration::Range { /** Gets the name of the cryptographic algorithm (for example `"RSA"` or `"AES"`). */ - string getName() { result = range.getName() } + string getName() { result = super.getName() } /** Gets the argument that specifies the size of the key in bits, if available. */ - DataFlow::Node getKeySizeArg() { result = range.getKeySizeArg() } + DataFlow::Node getKeySizeArg() { result = super.getKeySizeArg() } /** * Gets the size of the key generated (in bits), as well as the `origin` that * explains how we obtained this specific key size. */ int getKeySizeWithOrigin(DataFlow::Node origin) { - result = range.getKeySizeWithOrigin(origin) + result = super.getKeySizeWithOrigin(origin) } /** Gets the minimum key size (in bits) for this algorithm to be considered secure. */ - int minimumSecureKeySize() { result = range.minimumSecureKeySize() } + int minimumSecureKeySize() { result = super.minimumSecureKeySize() } } /** Provides classes for modeling new key-pair generation APIs. */ @@ -1230,16 +1147,12 @@ module Cryptography { * Extend this class to refine existing API models. If you want to model new APIs, * extend `CryptographicOperation::Range` instead. */ - class CryptographicOperation extends DataFlow::Node { - CryptographicOperation::Range range; - - CryptographicOperation() { this = range } - + class CryptographicOperation extends DataFlow::Node instanceof CryptographicOperation::Range { /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ - CryptographicAlgorithm getAlgorithm() { result = range.getAlgorithm() } + CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ - DataFlow::Node getAnInput() { result = range.getAnInput() } + DataFlow::Node getAnInput() { result = super.getAnInput() } } /** Provides classes for modeling new applications of a cryptographic algorithms. */ From c784f15762b8ea2f749e1f3d92fe29d498b63de3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 6 Apr 2022 15:40:04 +0200 Subject: [PATCH 082/171] Python: Rename more XML classes to follow convention - `XMLEtree` to `XmlEtree` - `XMLSax` to `XmlSax` - `LXML` to `Lxml` - `XMLParser` to `XmlParser` --- .../ql/lib/semmle/python/frameworks/Lxml.qll | 30 +++++++++---------- .../lib/semmle/python/frameworks/Stdlib.qll | 28 ++++++++--------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index 6d310563ade..24afbd199df 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -109,7 +109,7 @@ private module Lxml { * * See https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.XMLParser */ - module XMLParser { + module XmlParser { /** * A source of instances of `lxml.etree` parsers, extend this class to model new instances. * @@ -117,7 +117,7 @@ private module Lxml { * calls, or a special parameter that will be set when functions are called by an external * library. * - * Use the predicate `XMLParser::instance()` to get references to instances of `lxml.etree` parsers. + * Use the predicate `XmlParser::instance()` to get references to instances of `lxml.etree` parsers. */ abstract class InstanceSource extends DataFlow::LocalSourceNode { /** Holds if this instance is vulnerable to `kind`. */ @@ -129,8 +129,8 @@ private module Lxml { * * See https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.XMLParser */ - private class LXMLParser extends InstanceSource, DataFlow::CallCfgNode { - LXMLParser() { + private class LxmlParser extends InstanceSource, DataFlow::CallCfgNode { + LxmlParser() { this = API::moduleImport("lxml").getMember("etree").getMember("XMLParser").getACall() } @@ -159,8 +159,8 @@ private module Lxml { * * See https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.get_default_parser */ - private class LXMLDefaultParser extends InstanceSource, DataFlow::CallCfgNode { - LXMLDefaultParser() { + private class LxmlDefaultParser extends InstanceSource, DataFlow::CallCfgNode { + LxmlDefaultParser() { this = API::moduleImport("lxml").getMember("etree").getMember("get_default_parser").getACall() } @@ -196,8 +196,8 @@ private module Lxml { /** * A call to the `feed` method of an `lxml` parser. */ - private class LXMLParserFeedCall extends DataFlow::MethodCallNode, XML::XmlParsing::Range { - LXMLParserFeedCall() { this.calls(instance(_), "feed") } + private class LxmlParserFeedCall extends DataFlow::MethodCallNode, XML::XmlParsing::Range { + LxmlParserFeedCall() { this.calls(instance(_), "feed") } override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } @@ -233,8 +233,8 @@ private module Lxml { * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parse * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parseid */ - private class LXMLParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { - LXMLParsing() { + private class LxmlParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { + LxmlParsing() { this = API::moduleImport("lxml") .getMember("etree") @@ -257,7 +257,7 @@ private module Lxml { DataFlow::Node getParserArg() { result in [this.getArg(1), this.getArgByName("parser")] } override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { - this.getParserArg() = XMLParser::instanceVulnerableTo(kind) + this.getParserArg() = XmlParser::instanceVulnerableTo(kind) or kind.isXxe() and not exists(this.getParserArg()) @@ -284,8 +284,8 @@ private module Lxml { * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parse * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parseid */ - private class FileAccessFromLXMLParsing extends LXMLParsing, FileSystemAccess::Range { - FileAccessFromLXMLParsing() { + private class FileAccessFromLxmlParsing extends LxmlParsing, FileSystemAccess::Range { + FileAccessFromLxmlParsing() { this = API::moduleImport("lxml").getMember("etree").getMember(["parse", "parseid"]).getACall() // I considered whether we should try to reduce FPs from people passing file-like // objects, which will not be a file system access (and couldn't cause a @@ -305,9 +305,9 @@ private module Lxml { * See * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.iterparse */ - private class LXMLIterparseCall extends DataFlow::CallCfgNode, XML::XmlParsing::Range, + private class LxmlIterparseCall extends DataFlow::CallCfgNode, XML::XmlParsing::Range, FileSystemAccess::Range { - LXMLIterparseCall() { + LxmlIterparseCall() { this = API::moduleImport("lxml").getMember("etree").getMember("iterparse").getACall() } diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 91ba7bc75b5..8508aaef5f0 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3191,7 +3191,7 @@ private module StdlibPrivate { * - https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.XMLParser * - https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.XMLPullParser */ - module XMLParser { + module XmlParser { /** * A source of instances of `xml.etree` parsers, extend this class to model new instances. * @@ -3199,7 +3199,7 @@ private module StdlibPrivate { * calls, or a special parameter that will be set when functions are called by an external * library. * - * Use the predicate `XMLParser::instance()` to get references to instances of `xml.etree` parsers. + * Use the predicate `XmlParser::instance()` to get references to instances of `xml.etree` parsers. */ abstract class InstanceSource extends DataFlow::LocalSourceNode { } @@ -3236,8 +3236,8 @@ private module StdlibPrivate { /** * A call to the `feed` method of an `xml.etree` parser. */ - private class XMLEtreeParserFeedCall extends DataFlow::MethodCallNode, XML::XmlParsing::Range { - XMLEtreeParserFeedCall() { this.calls(instance(), "feed") } + private class XmlEtreeParserFeedCall extends DataFlow::MethodCallNode, XML::XmlParsing::Range { + XmlEtreeParserFeedCall() { this.calls(instance(), "feed") } override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } @@ -3274,8 +3274,8 @@ private module StdlibPrivate { * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.parse * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.iterparse */ - private class XMLEtreeParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { - XMLEtreeParsing() { + private class XmlEtreeParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { + XmlEtreeParsing() { this = API::moduleImport("xml") .getMember("etree") @@ -3325,8 +3325,8 @@ private module StdlibPrivate { * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.parse * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.iterparse */ - private class FileAccessFromXMLEtreeParsing extends XMLEtreeParsing, FileSystemAccess::Range { - FileAccessFromXMLEtreeParsing() { + private class FileAccessFromXmlEtreeParsing extends XmlEtreeParsing, FileSystemAccess::Range { + FileAccessFromXmlEtreeParsing() { this = API::moduleImport("xml") .getMember("etree") @@ -3445,9 +3445,9 @@ private module StdlibPrivate { * * See https://docs.python.org/3/library/xml.sax.reader.html#xml.sax.xmlreader.XMLReader.parse */ - private class XMLSaxInstanceParsing extends DataFlow::MethodCallNode, XML::XmlParsing::Range, + private class XmlSaxInstanceParsing extends DataFlow::MethodCallNode, XML::XmlParsing::Range, FileSystemAccess::Range { - XMLSaxInstanceParsing() { + XmlSaxInstanceParsing() { this = API::moduleImport("xml") .getMember("sax") @@ -3496,8 +3496,8 @@ private module StdlibPrivate { * - https://docs.python.org/3.10/library/xml.sax.html#xml.sax.parse * - https://docs.python.org/3.10/library/xml.sax.html#xml.sax.parseString */ - private class XMLSaxParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { - XMLSaxParsing() { + private class XmlSaxParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { + XmlSaxParsing() { this = API::moduleImport("xml").getMember("sax").getMember(["parse", "parseString"]).getACall() } @@ -3535,8 +3535,8 @@ private module StdlibPrivate { * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.parse * - https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.iterparse */ - private class FileAccessFromXMLSaxParsing extends XMLSaxParsing, FileSystemAccess::Range { - FileAccessFromXMLSaxParsing() { + private class FileAccessFromXmlSaxParsing extends XmlSaxParsing, FileSystemAccess::Range { + FileAccessFromXmlSaxParsing() { this = API::moduleImport("xml").getMember("sax").getMember("parse").getACall() // I considered whether we should try to reduce FPs from people passing file-like // objects, which will not be a file system access (and couldn't cause a From f2f0873d911dc9bb685fa708707e3f4c1de6fc9d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 6 Apr 2022 15:49:06 +0200 Subject: [PATCH 083/171] Python: Use new `API::CallNode` for XML constant check This also means that the detection of the values passed to these keyword arguments will no longer just be from a local scope, but can also be across function boundaries. --- .../ql/lib/semmle/python/frameworks/Lxml.qll | 21 ++++++++++--------- .../semmle/python/frameworks/Xmltodict.qll | 4 ++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index 24afbd199df..a77da9e7915 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -129,7 +129,7 @@ private module Lxml { * * See https://lxml.de/apidoc/lxml.etree.html?highlight=xmlparser#lxml.etree.XMLParser */ - private class LxmlParser extends InstanceSource, DataFlow::CallCfgNode { + private class LxmlParser extends InstanceSource, API::CallNode { LxmlParser() { this = API::moduleImport("lxml").getMember("etree").getMember("XMLParser").getACall() } @@ -141,16 +141,17 @@ private module Lxml { // resolve_entities has default True not exists(this.getArgByName("resolve_entities")) or - this.getArgByName("resolve_entities").getALocalSource().asExpr() = any(True t) + this.getKeywordParameter("resolve_entities").getAValueReachingRhs().asExpr() = any(True t) ) or (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and - this.getArgByName("huge_tree").getALocalSource().asExpr() = any(True t) and - not this.getArgByName("resolve_entities").getALocalSource().asExpr() = any(False t) + this.getKeywordParameter("huge_tree").getAValueReachingRhs().asExpr() = any(True t) and + not this.getKeywordParameter("resolve_entities").getAValueReachingRhs().asExpr() = + any(False t) or kind.isDtdRetrieval() and - this.getArgByName("load_dtd").getALocalSource().asExpr() = any(True t) and - this.getArgByName("no_network").getALocalSource().asExpr() = any(False t) + this.getKeywordParameter("load_dtd").getAValueReachingRhs().asExpr() = any(True t) and + this.getKeywordParameter("no_network").getAValueReachingRhs().asExpr() = any(False t) } } @@ -305,7 +306,7 @@ private module Lxml { * See * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.iterparse */ - private class LxmlIterparseCall extends DataFlow::CallCfgNode, XML::XmlParsing::Range, + private class LxmlIterparseCall extends API::CallNode, XML::XmlParsing::Range, FileSystemAccess::Range { LxmlIterparseCall() { this = API::moduleImport("lxml").getMember("etree").getMember("iterparse").getACall() @@ -318,11 +319,11 @@ private module Lxml { kind.isXxe() or (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and - this.getArgByName("huge_tree").getALocalSource().asExpr() = any(True t) + this.getKeywordParameter("huge_tree").getAValueReachingRhs().asExpr() = any(True t) or kind.isDtdRetrieval() and - this.getArgByName("load_dtd").getALocalSource().asExpr() = any(True t) and - this.getArgByName("no_network").getALocalSource().asExpr() = any(False t) + this.getKeywordParameter("load_dtd").getAValueReachingRhs().asExpr() = any(True t) and + this.getKeywordParameter("no_network").getAValueReachingRhs().asExpr() = any(False t) } override predicate mayExecuteInput() { none() } diff --git a/python/ql/lib/semmle/python/frameworks/Xmltodict.qll b/python/ql/lib/semmle/python/frameworks/Xmltodict.qll index db2c443d8e9..95d44d6d1b0 100644 --- a/python/ql/lib/semmle/python/frameworks/Xmltodict.qll +++ b/python/ql/lib/semmle/python/frameworks/Xmltodict.qll @@ -20,7 +20,7 @@ private module Xmltodict { /** * A call to `xmltodict.parse`. */ - private class XMLtoDictParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { + private class XMLtoDictParsing extends API::CallNode, XML::XmlParsing::Range { XMLtoDictParsing() { this = API::moduleImport("xmltodict").getMember("parse").getACall() } override DataFlow::Node getAnInput() { @@ -29,7 +29,7 @@ private module Xmltodict { override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and - this.getArgByName("disable_entities").getALocalSource().asExpr() = any(False f) + this.getKeywordParameter("disable_entities").getAValueReachingRhs().asExpr() = any(False f) } override predicate mayExecuteInput() { none() } From 7728b6cf1b750eadf462606dbc3ca0660e86417d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 7 Apr 2022 10:45:43 +0200 Subject: [PATCH 084/171] Python: Change XmlBomb vulnerability kind --- python/ql/lib/semmle/python/Concepts.qll | 19 ++++++---- .../ql/lib/semmle/python/frameworks/Lxml.qll | 4 +- .../lib/semmle/python/frameworks/Stdlib.qll | 12 +++--- .../semmle/python/frameworks/Xmltodict.qll | 2 +- .../Security/CWE-611/SimpleXmlRpcServer.ql | 12 ++---- .../dataflow/XmlBombCustomizations.qll | 2 +- .../library-tests/frameworks/lxml/parsing.py | 4 +- .../frameworks/stdlib/XPathExecution.py | 6 +-- .../frameworks/stdlib/xml_dom.py | 24 ++++++------ .../frameworks/stdlib/xml_etree.py | 38 +++++++++---------- .../frameworks/stdlib/xml_sax.py | 26 ++++++------- .../frameworks/xmltodict/test.py | 2 +- 12 files changed, 73 insertions(+), 78 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index eec0cd0d1a0..4fadc953c3b 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -507,15 +507,18 @@ module XML { * See PoC at `python/PoCs/XmlParsing/PoC.py` for some tests of vulnerable XML parsing. */ class XmlParsingVulnerabilityKind extends string { - XmlParsingVulnerabilityKind() { - this in ["Billion Laughs", "Quadratic Blowup", "XXE", "DTD retrieval"] - } + XmlParsingVulnerabilityKind() { this in ["XML bomb", "XXE", "DTD retrieval"] } - /** Holds for Billion Laughs vulnerability kind. */ - predicate isBillionLaughs() { this = "Billion Laughs" } - - /** Holds for Quadratic Blowup vulnerability kind. */ - predicate isQuadraticBlowup() { this = "Quadratic Blowup" } + /** + * Holds for XML bomb vulnerability kind, such as 'Billion Laughs' and 'Quadratic + * Blowup'. + * + * While a parser could technically be vulnerable to one and not the other, from our + * point of view the interesting part is that it IS vulnerable to these types of + * attacks, and not so much which one specifically works. In practice I haven't seen + * a parser that is vulnerable to one and not the other. + */ + predicate isXmlBomb() { this = "XML bomb" } /** Holds for XXE vulnerability kind. */ predicate isXxe() { this = "XXE" } diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index a77da9e7915..cfb83fd5732 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -144,7 +144,7 @@ private module Lxml { this.getKeywordParameter("resolve_entities").getAValueReachingRhs().asExpr() = any(True t) ) or - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and + kind.isXmlBomb() and this.getKeywordParameter("huge_tree").getAValueReachingRhs().asExpr() = any(True t) and not this.getKeywordParameter("resolve_entities").getAValueReachingRhs().asExpr() = any(False t) @@ -318,7 +318,7 @@ private module Lxml { // note that there is no `resolve_entities` argument, so it's not possible to turn off XXE :O kind.isXxe() or - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and + kind.isXmlBomb() and this.getKeywordParameter("huge_tree").getAValueReachingRhs().asExpr() = any(True t) or kind.isDtdRetrieval() and diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 8508aaef5f0..f4b6915d440 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3241,9 +3241,7 @@ private module StdlibPrivate { override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] } - override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { - kind.isBillionLaughs() or kind.isQuadraticBlowup() - } + override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { kind.isXmlBomb() } override predicate mayExecuteInput() { none() } @@ -3301,7 +3299,7 @@ private module StdlibPrivate { override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { // note: it does not matter what `xml.etree` parser you are using, you cannot // change the security features anyway :| - kind.isBillionLaughs() or kind.isQuadraticBlowup() + kind.isXmlBomb() } override predicate mayExecuteInput() { none() } @@ -3461,7 +3459,7 @@ private module StdlibPrivate { override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { // always vuln to these - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) + kind.isXmlBomb() or // can be vuln to other things if features has been turned on this.getObject() = saxParserWithFeatureExternalGesTurnedOn() and @@ -3514,7 +3512,7 @@ private module StdlibPrivate { override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { // always vuln to these - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) + kind.isXmlBomb() } override predicate mayExecuteInput() { none() } @@ -3590,7 +3588,7 @@ private module StdlibPrivate { this.getParserArg() = saxParserWithFeatureExternalGesTurnedOn() and (kind.isXxe() or kind.isDtdRetrieval()) or - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) + kind.isXmlBomb() } override predicate mayExecuteInput() { none() } diff --git a/python/ql/lib/semmle/python/frameworks/Xmltodict.qll b/python/ql/lib/semmle/python/frameworks/Xmltodict.qll index 95d44d6d1b0..f63fec7afe4 100644 --- a/python/ql/lib/semmle/python/frameworks/Xmltodict.qll +++ b/python/ql/lib/semmle/python/frameworks/Xmltodict.qll @@ -28,7 +28,7 @@ private module Xmltodict { } override predicate vulnerableTo(XML::XmlParsingVulnerabilityKind kind) { - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and + kind.isXmlBomb() and this.getKeywordParameter("disable_entities").getAValueReachingRhs().asExpr() = any(False f) } diff --git a/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql b/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql index e638c13853f..e31fdc88629 100644 --- a/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql +++ b/python/ql/src/experimental/Security/CWE-611/SimpleXmlRpcServer.ql @@ -13,13 +13,7 @@ private import python private import semmle.python.Concepts private import semmle.python.ApiGraphs -from DataFlow::CallCfgNode call, string kinds +from DataFlow::CallCfgNode call where - call = API::moduleImport("xmlrpc").getMember("server").getMember("SimpleXMLRPCServer").getACall() and - kinds = - strictconcat(XML::XmlParsingVulnerabilityKind kind | - kind.isBillionLaughs() or kind.isQuadraticBlowup() - | - kind, ", " - ) -select call, "SimpleXMLRPCServer is vulnerable to: " + kinds + "." + call = API::moduleImport("xmlrpc").getMember("server").getMember("SimpleXMLRPCServer").getACall() +select call, "SimpleXMLRPCServer is vulnerable to XML bombs" diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll index 05f6fc57a34..7cc4ec5bad5 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll @@ -41,7 +41,7 @@ module XmlBomb { class XmlParsingWithEntityResolution extends Sink { XmlParsingWithEntityResolution() { exists(XML::XmlParsing parsing, XML::XmlParsingVulnerabilityKind kind | - (kind.isBillionLaughs() or kind.isQuadraticBlowup()) and + kind.isXmlBomb() and parsing.vulnerableTo(kind) and this = parsing.getAnInput() ) diff --git a/python/ql/test/library-tests/frameworks/lxml/parsing.py b/python/ql/test/library-tests/frameworks/lxml/parsing.py index ca68c99a90e..63cdc79b4c1 100644 --- a/python/ql/test/library-tests/frameworks/lxml/parsing.py +++ b/python/ql/test/library-tests/frameworks/lxml/parsing.py @@ -50,7 +50,7 @@ lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVu # Billion laughs vuln (also XXE) parser = lxml.etree.XMLParser(huge_tree=True) -lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=lxml.etree.fromstring(..) +lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' xmlVuln='XXE' decodeOutput=lxml.etree.fromstring(..) # Safe for both Billion laughs and XXE parser = lxml.etree.XMLParser(resolve_entities=False, huge_tree=True) @@ -63,5 +63,5 @@ lxml.etree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVu # iterparse configurations ... this doesn't use a parser argument but takes MOST (!) of # the normal XMLParser arguments. Specifically, it doesn't allow disabling XXE :O -lxml.etree.iterparse(xml_file, huge_tree=True) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) getAPathArgument=xml_file +lxml.etree.iterparse(xml_file, huge_tree=True) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='XML bomb' xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) getAPathArgument=xml_file lxml.etree.iterparse(xml_file, load_dtd=True, no_network=False) # $ decodeFormat=XML decodeInput=xml_file xmlVuln='DTD retrieval' xmlVuln='XXE' decodeOutput=lxml.etree.iterparse(..) getAPathArgument=xml_file diff --git a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py index 5faff5ed868..bf7dd08185b 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py +++ b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py @@ -2,7 +2,7 @@ match = "dc:title" ns = {'dc': 'http://purl.org/dc/elements/1.1/'} import xml.etree.ElementTree as ET -tree = ET.parse('country_data.xml') # $ decodeFormat=XML decodeInput='country_data.xml' decodeOutput=ET.parse(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument='country_data.xml' +tree = ET.parse('country_data.xml') # $ decodeFormat=XML decodeInput='country_data.xml' decodeOutput=ET.parse(..) xmlVuln='XML bomb' getAPathArgument='country_data.xml' root = tree.getroot() root.find(match, namespaces=ns) # $ getXPath=match @@ -10,13 +10,13 @@ root.findall(match, namespaces=ns) # $ getXPath=match root.findtext(match, default=None, namespaces=ns) # $ getXPath=match tree = ET.ElementTree() -tree.parse("index.xhtml") # $ decodeFormat=XML decodeInput="index.xhtml" decodeOutput=tree.parse(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument="index.xhtml" +tree.parse("index.xhtml") # $ decodeFormat=XML decodeInput="index.xhtml" decodeOutput=tree.parse(..) xmlVuln='XML bomb' getAPathArgument="index.xhtml" tree.find(match, namespaces=ns) # $ getXPath=match tree.findall(match, namespaces=ns) # $ getXPath=match tree.findtext(match, default=None, namespaces=ns) # $ getXPath=match parser = ET.XMLParser() -parser.feed("bar") # $ decodeFormat=XML decodeInput="bar" xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.feed("bar") # $ decodeFormat=XML decodeInput="bar" xmlVuln='XML bomb' tree = parser.close() # $ decodeOutput=parser.close() tree.find(match, namespaces=ns) # $ getXPath=match diff --git a/python/ql/test/library-tests/frameworks/stdlib/xml_dom.py b/python/ql/test/library-tests/frameworks/stdlib/xml_dom.py index b3a1ab7f930..8d511c51733 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/xml_dom.py +++ b/python/ql/test/library-tests/frameworks/stdlib/xml_dom.py @@ -6,26 +6,26 @@ import xml.sax x = "some xml" # minidom -xml.dom.minidom.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) -xml.dom.minidom.parse(file=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) +xml.dom.minidom.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) +xml.dom.minidom.parse(file=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) -xml.dom.minidom.parseString(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parseString(..) -xml.dom.minidom.parseString(string=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.minidom.parseString(..) +xml.dom.minidom.parseString(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xml.dom.minidom.parseString(..) +xml.dom.minidom.parseString(string=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xml.dom.minidom.parseString(..) # pulldom -xml.dom.pulldom.parse(StringIO(x))['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) -xml.dom.pulldom.parse(stream_or_string=StringIO(x))['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) +xml.dom.pulldom.parse(StringIO(x))['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) +xml.dom.pulldom.parse(stream_or_string=StringIO(x))['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) -xml.dom.pulldom.parseString(x)['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parseString(..) -xml.dom.pulldom.parseString(string=x)['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.dom.pulldom.parseString(..) +xml.dom.pulldom.parseString(x)['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xml.dom.pulldom.parseString(..) +xml.dom.pulldom.parseString(string=x)['START_DOCUMENT'][1] # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xml.dom.pulldom.parseString(..) # These are based on SAX parses, and you can specify your own, so you can expose yourself to XXE (yay/) parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) -xml.dom.minidom.parse(StringIO(x), parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) -xml.dom.minidom.parse(StringIO(x), parser=parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) +xml.dom.minidom.parse(StringIO(x), parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' xmlVuln='DTD retrieval' xmlVuln='XXE' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) +xml.dom.minidom.parse(StringIO(x), parser=parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' xmlVuln='DTD retrieval' xmlVuln='XXE' decodeOutput=xml.dom.minidom.parse(..) getAPathArgument=StringIO(..) -xml.dom.pulldom.parse(StringIO(x), parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) -xml.dom.pulldom.parse(StringIO(x), parser=parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) +xml.dom.pulldom.parse(StringIO(x), parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' xmlVuln='DTD retrieval' xmlVuln='XXE' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) +xml.dom.pulldom.parse(StringIO(x), parser=parser) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' xmlVuln='DTD retrieval' xmlVuln='XXE' decodeOutput=xml.dom.pulldom.parse(..) getAPathArgument=StringIO(..) diff --git a/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py b/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py index 00f3b964b18..441f9adc87a 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py +++ b/python/ql/test/library-tests/frameworks/stdlib/xml_etree.py @@ -4,43 +4,43 @@ import xml.etree.ElementTree x = "some xml" # Parsing in different ways -xml.etree.ElementTree.fromstring(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.fromstring(..) -xml.etree.ElementTree.fromstring(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.fromstring(..) +xml.etree.ElementTree.fromstring(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.fromstring(..) +xml.etree.ElementTree.fromstring(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.fromstring(..) -xml.etree.ElementTree.fromstringlist([x]) # $ decodeFormat=XML decodeInput=List xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.fromstringlist(..) -xml.etree.ElementTree.fromstringlist(sequence=[x]) # $ decodeFormat=XML decodeInput=List xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.fromstringlist(..) +xml.etree.ElementTree.fromstringlist([x]) # $ decodeFormat=XML decodeInput=List xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.fromstringlist(..) +xml.etree.ElementTree.fromstringlist(sequence=[x]) # $ decodeFormat=XML decodeInput=List xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.fromstringlist(..) -xml.etree.ElementTree.XML(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.XML(..) -xml.etree.ElementTree.XML(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.XML(..) +xml.etree.ElementTree.XML(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.XML(..) +xml.etree.ElementTree.XML(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.XML(..) -xml.etree.ElementTree.XMLID(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.XMLID(..) -xml.etree.ElementTree.XMLID(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.XMLID(..) +xml.etree.ElementTree.XMLID(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.XMLID(..) +xml.etree.ElementTree.XMLID(text=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.XMLID(..) -xml.etree.ElementTree.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.parse(..) getAPathArgument=StringIO(..) -xml.etree.ElementTree.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.parse(..) getAPathArgument=StringIO(..) +xml.etree.ElementTree.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.parse(..) getAPathArgument=StringIO(..) +xml.etree.ElementTree.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.parse(..) getAPathArgument=StringIO(..) -xml.etree.ElementTree.iterparse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.iterparse(..) getAPathArgument=StringIO(..) -xml.etree.ElementTree.iterparse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.iterparse(..) getAPathArgument=StringIO(..) +xml.etree.ElementTree.iterparse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.iterparse(..) getAPathArgument=StringIO(..) +xml.etree.ElementTree.iterparse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.iterparse(..) getAPathArgument=StringIO(..) tree = xml.etree.ElementTree.ElementTree() -tree.parse("file.xml") # $ decodeFormat=XML decodeInput="file.xml" xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=tree.parse(..) getAPathArgument="file.xml" -tree.parse(source="file.xml") # $ decodeFormat=XML decodeInput="file.xml" xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=tree.parse(..) getAPathArgument="file.xml" +tree.parse("file.xml") # $ decodeFormat=XML decodeInput="file.xml" xmlVuln='XML bomb' decodeOutput=tree.parse(..) getAPathArgument="file.xml" +tree.parse(source="file.xml") # $ decodeFormat=XML decodeInput="file.xml" xmlVuln='XML bomb' decodeOutput=tree.parse(..) getAPathArgument="file.xml" # With parsers (no options available to disable/enable security features) parser = xml.etree.ElementTree.XMLParser() -xml.etree.ElementTree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xml.etree.ElementTree.fromstring(..) +xml.etree.ElementTree.fromstring(x, parser=parser) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xml.etree.ElementTree.fromstring(..) # manual use of feed method parser = xml.etree.ElementTree.XMLParser() -parser.feed(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -parser.feed(data=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.feed(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' +parser.feed(data=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' parser.close() # $ decodeOutput=parser.close() # manual use of feed method on XMLPullParser parser = xml.etree.ElementTree.XMLPullParser() -parser.feed(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -parser.feed(data=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +parser.feed(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' +parser.feed(data=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' parser.close() # $ decodeOutput=parser.close() # note: it's technically possible to use the thing wrapper func `fromstring` with an diff --git a/python/ql/test/library-tests/frameworks/stdlib/xml_sax.py b/python/ql/test/library-tests/frameworks/stdlib/xml_sax.py index c08034907a4..6199fd76cc1 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/xml_sax.py +++ b/python/ql/test/library-tests/frameworks/stdlib/xml_sax.py @@ -10,41 +10,41 @@ class MainHandler(xml.sax.ContentHandler): def characters(self, data): self._result.append(data) -xml.sax.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) -xml.sax.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) +xml.sax.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' getAPathArgument=StringIO(..) +xml.sax.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' getAPathArgument=StringIO(..) -xml.sax.parseString(x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' -xml.sax.parseString(string=x) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' +xml.sax.parseString(x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' +xml.sax.parseString(string=x) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' parser = xml.sax.make_parser() -parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) -parser.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' getAPathArgument=StringIO(..) +parser.parse(source=StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' getAPathArgument=StringIO(..) # You can make it vuln to both XXE and DTD retrieval by setting this flag # see https://docs.python.org/3/library/xml.sax.handler.html#xml.sax.handler.feature_external_ges parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) -parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' getAPathArgument=StringIO(..) +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' xmlVuln='DTD retrieval' xmlVuln='XXE' getAPathArgument=StringIO(..) parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, False) -parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' getAPathArgument=StringIO(..) # Forward Type Tracking test def func(cond): parser = xml.sax.make_parser() if cond: parser.setFeature(xml.sax.handler.feature_external_ges, True) - parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' getAPathArgument=StringIO(..) + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' xmlVuln='DTD retrieval' xmlVuln='XXE' getAPathArgument=StringIO(..) else: - parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' getAPathArgument=StringIO(..) # make it vuln, then making it safe # a bit of an edge-case, but is nice to be able to handle. parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, True) parser.setFeature(xml.sax.handler.feature_external_ges, False) -parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' getAPathArgument=StringIO(..) +parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' getAPathArgument=StringIO(..) def check_conditional_assignment(cond): parser = xml.sax.make_parser() @@ -52,7 +52,7 @@ def check_conditional_assignment(cond): parser.setFeature(xml.sax.handler.feature_external_ges, True) else: parser.setFeature(xml.sax.handler.feature_external_ges, False) - parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' getAPathArgument=StringIO(..) + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' xmlVuln='DTD retrieval' xmlVuln='XXE' getAPathArgument=StringIO(..) def check_conditional_assignment2(cond): parser = xml.sax.make_parser() @@ -61,4 +61,4 @@ def check_conditional_assignment2(cond): else: flag_value = False parser.setFeature(xml.sax.handler.feature_external_ges, flag_value) - parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='Billion Laughs' xmlVuln='DTD retrieval' xmlVuln='Quadratic Blowup' xmlVuln='XXE' getAPathArgument=StringIO(..) + parser.parse(StringIO(x)) # $ decodeFormat=XML decodeInput=StringIO(..) xmlVuln='XML bomb' xmlVuln='DTD retrieval' xmlVuln='XXE' getAPathArgument=StringIO(..) diff --git a/python/ql/test/library-tests/frameworks/xmltodict/test.py b/python/ql/test/library-tests/frameworks/xmltodict/test.py index 01dc2f3c484..ef236f7796c 100644 --- a/python/ql/test/library-tests/frameworks/xmltodict/test.py +++ b/python/ql/test/library-tests/frameworks/xmltodict/test.py @@ -5,4 +5,4 @@ x = "some xml" xmltodict.parse(x) # $ decodeFormat=XML decodeInput=x decodeOutput=xmltodict.parse(..) xmltodict.parse(xml_input=x) # $ decodeFormat=XML decodeInput=x decodeOutput=xmltodict.parse(..) -xmltodict.parse(x, disable_entities=False) # $ decodeFormat=XML decodeInput=x xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup' decodeOutput=xmltodict.parse(..) +xmltodict.parse(x, disable_entities=False) # $ decodeFormat=XML decodeInput=x xmlVuln='XML bomb' decodeOutput=xmltodict.parse(..) From 405480c41045f943e025aa7d21a33b971b231cf2 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 7 Apr 2022 15:34:56 +0200 Subject: [PATCH 085/171] Python: Rename sink definitions for XXE/XML bomb --- .../python/security/dataflow/XmlBombCustomizations.qll | 7 +++---- .../semmle/python/security/dataflow/XxeCustomizations.qll | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll index 7cc4ec5bad5..a2fe1b8ecb2 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll @@ -35,11 +35,10 @@ module XmlBomb { } /** - * A call to an XML parser that performs internal entity expansion, viewed - * as a data flow sink for XML-bomb vulnerabilities. + * A call to an XML parser that is vulnerable to XML bombs. */ - class XmlParsingWithEntityResolution extends Sink { - XmlParsingWithEntityResolution() { + class XmlParsingVulnerableToXmlBomb extends Sink { + XmlParsingVulnerableToXmlBomb() { exists(XML::XmlParsing parsing, XML::XmlParsingVulnerabilityKind kind | kind.isXmlBomb() and parsing.vulnerableTo(kind) and diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll index 0fc139ec4f3..1d1ad087f84 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll @@ -35,11 +35,10 @@ module Xxe { } /** - * A call to an XML parser that performs external entity expansion, viewed - * as a data flow sink for XXE vulnerabilities. + * A call to an XML parser that is vulnerable to XXE. */ - class XmlParsingWithExternalEntityResolution extends Sink { - XmlParsingWithExternalEntityResolution() { + class XmlParsingVulnerableToXxe extends Sink { + XmlParsingVulnerableToXxe() { exists(XML::XmlParsing parsing, XML::XmlParsingVulnerabilityKind kind | kind.isXxe() and parsing.vulnerableTo(kind) and From 8191be9d7506bec7909a19f001276d2716d4f600 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 7 Apr 2022 15:36:04 +0200 Subject: [PATCH 086/171] Python: Move last XXE/XML bomb out of experimental --- .../semmle/python/security/dataflow/XmlBombCustomizations.qll | 0 .../semmle/python/security/dataflow/XmlBombQuery.qll | 0 .../semmle/python/security/dataflow/XxeCustomizations.qll | 0 .../semmle/python/security/dataflow/XxeQuery.qll | 0 python/ql/src/Security/CWE-611/Xxe.ql | 2 +- python/ql/src/Security/CWE-776/XmlBomb.ql | 2 +- 6 files changed, 2 insertions(+), 2 deletions(-) rename python/ql/{src/experimental => lib}/semmle/python/security/dataflow/XmlBombCustomizations.qll (100%) rename python/ql/{src/experimental => lib}/semmle/python/security/dataflow/XmlBombQuery.qll (100%) rename python/ql/{src/experimental => lib}/semmle/python/security/dataflow/XxeCustomizations.qll (100%) rename python/ql/{src/experimental => lib}/semmle/python/security/dataflow/XxeQuery.qll (100%) diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/XmlBombCustomizations.qll similarity index 100% rename from python/ql/src/experimental/semmle/python/security/dataflow/XmlBombCustomizations.qll rename to python/ql/lib/semmle/python/security/dataflow/XmlBombCustomizations.qll diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XmlBombQuery.qll b/python/ql/lib/semmle/python/security/dataflow/XmlBombQuery.qll similarity index 100% rename from python/ql/src/experimental/semmle/python/security/dataflow/XmlBombQuery.qll rename to python/ql/lib/semmle/python/security/dataflow/XmlBombQuery.qll diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/XxeCustomizations.qll similarity index 100% rename from python/ql/src/experimental/semmle/python/security/dataflow/XxeCustomizations.qll rename to python/ql/lib/semmle/python/security/dataflow/XxeCustomizations.qll diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/XxeQuery.qll b/python/ql/lib/semmle/python/security/dataflow/XxeQuery.qll similarity index 100% rename from python/ql/src/experimental/semmle/python/security/dataflow/XxeQuery.qll rename to python/ql/lib/semmle/python/security/dataflow/XxeQuery.qll diff --git a/python/ql/src/Security/CWE-611/Xxe.ql b/python/ql/src/Security/CWE-611/Xxe.ql index f706ea6e909..5cc6da25467 100644 --- a/python/ql/src/Security/CWE-611/Xxe.ql +++ b/python/ql/src/Security/CWE-611/Xxe.ql @@ -13,7 +13,7 @@ */ import python -import experimental.semmle.python.security.dataflow.XxeQuery +import semmle.python.security.dataflow.XxeQuery import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink diff --git a/python/ql/src/Security/CWE-776/XmlBomb.ql b/python/ql/src/Security/CWE-776/XmlBomb.ql index 2a1ea5916c4..54d483db17e 100644 --- a/python/ql/src/Security/CWE-776/XmlBomb.ql +++ b/python/ql/src/Security/CWE-776/XmlBomb.ql @@ -13,7 +13,7 @@ */ import python -import experimental.semmle.python.security.dataflow.XmlBombQuery +import semmle.python.security.dataflow.XmlBombQuery import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink From 30fff1cf8b23e57d32417e4d89b516b0180d5810 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 7 Apr 2022 16:02:41 +0200 Subject: [PATCH 087/171] Python: Merge pymongo NoSQL tests --- .../Security/CWE-943/NoSQLInjection.expected | 24 +++++++++---------- .../Security/CWE-943/pymongo_bad.py | 17 ------------- .../{pymongo_good.py => pymongo_test.py} | 17 +++++++++---- 3 files changed, 25 insertions(+), 33 deletions(-) delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py rename python/ql/test/experimental/query-tests/Security/CWE-943/{pymongo_good.py => pymongo_test.py} (57%) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected index 6fa158370a6..5213b12744d 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected @@ -44,11 +44,11 @@ edges | mongoengine_bad.py:57:21:57:42 | ControlFlowNode for Subscript | mongoengine_bad.py:58:30:58:42 | ControlFlowNode for unsafe_search | | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | | mongoengine_bad.py:58:30:58:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | -| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | -| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | -| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | -| pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | -| pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | +| pymongo_test.py:12:21:12:27 | ControlFlowNode for request | pymongo_test.py:12:21:12:32 | ControlFlowNode for Attribute | +| pymongo_test.py:12:21:12:32 | ControlFlowNode for Attribute | pymongo_test.py:12:21:12:42 | ControlFlowNode for Subscript | +| pymongo_test.py:12:21:12:42 | ControlFlowNode for Subscript | pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | +| pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | +| pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | nodes | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | flask_mongoengine_bad.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | @@ -104,12 +104,12 @@ nodes | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | mongoengine_bad.py:58:30:58:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| pymongo_test.py:12:21:12:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| pymongo_test.py:12:21:12:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| pymongo_test.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | +| pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | subpaths #select | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | This | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | user-provided value | @@ -121,4 +121,4 @@ subpaths | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | user-provided value | | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | user-provided value | | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | This | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | user-provided value | -| pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | This | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value | +| pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | This | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py deleted file mode 100644 index da16df828b8..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py +++ /dev/null @@ -1,17 +0,0 @@ -from flask import Flask, request -from pymongo import MongoClient -import json - -app = Flask(__name__) -client = MongoClient() - - -@app.route("/") -def home_page(): - unsafe_search = request.args['search'] - json_search = json.loads(unsafe_search) - - return client.db.collection.find_one({'data': json_search}) - -# if __name__ == "__main__": -# app.run(debug=True) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_test.py similarity index 57% rename from python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_good.py rename to python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_test.py index 5b112e12385..300567ac8c3 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_good.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_test.py @@ -7,13 +7,22 @@ app = Flask(__name__) client = MongoClient() -@app.route("/") -def home_page(): +@app.route("/bad") +def bad(): + unsafe_search = request.args['search'] + json_search = json.loads(unsafe_search) + + return client.db.collection.find_one({'data': json_search}) + + +@app.route("/good") +def good(): unsafe_search = request.args['search'] json_search = json.loads(unsafe_search) safe_search = sanitize(json_search) return client.db.collection.find_one({'data': safe_search}) -# if __name__ == "__main__": -# app.run(debug=True) + +if __name__ == "__main__": + app.run(debug=True) From 81fdc1bd78c55bfb215b608b700a88dc21cdcdb0 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 7 Apr 2022 16:07:02 +0200 Subject: [PATCH 088/171] Python: Add more `pymongo` NoSQL tests --- .../Security/CWE-943/NoSQLInjection.expected | 10 ++++++++++ .../Security/CWE-943/pymongo_test.py | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected index 5213b12744d..c39aea2345d 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected @@ -49,6 +49,10 @@ edges | pymongo_test.py:12:21:12:42 | ControlFlowNode for Subscript | pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | | pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | | pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | +| pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | +| pymongo_test.py:29:27:29:33 | ControlFlowNode for request | pymongo_test.py:29:27:29:38 | ControlFlowNode for Attribute | +| pymongo_test.py:29:27:29:38 | ControlFlowNode for Attribute | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | +| pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | nodes | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | flask_mongoengine_bad.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | @@ -110,6 +114,11 @@ nodes | pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| pymongo_test.py:29:27:29:33 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| pymongo_test.py:29:27:29:38 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | subpaths #select | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | This | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | user-provided value | @@ -122,3 +131,4 @@ subpaths | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | user-provided value | | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | This | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | user-provided value | | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | This | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | user-provided value | +| pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | This | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_test.py b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_test.py index 300567ac8c3..052c1c65d4f 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_test.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_test.py @@ -24,5 +24,23 @@ def good(): return client.db.collection.find_one({'data': safe_search}) +@app.route("/bad2") +def bad2(): + event_id = json.loads(request.args['event_id']) + client = MongoClient("localhost", 27017, maxPoolSize=50) + db = client.localhost + collection = db['collection'] + cursor = collection.find_one({"$where": f"this._id == '${event_id}'"}) + + +@app.route("/bad3") +def bad3(): + event_id = json.loads(request.args['event_id']) + client = MongoClient("localhost", 27017, maxPoolSize=50) + db = client.get_database(name="localhost") + collection = db['collection'] + cursor = collection.find_one({"$where": f"this._id == '${event_id}'"}) + + if __name__ == "__main__": app.run(debug=True) From 0ce2ced1aadf28e38c518a8786eeab42fa829197 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 7 Apr 2022 16:16:10 +0200 Subject: [PATCH 089/171] Python: Model `pymongo.mongo_client.MongoClient` --- python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll index bdd067218b3..99681c8502d 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll @@ -15,6 +15,10 @@ private module NoSql { /** Gets a reference to `pymongo.MongoClient` */ private API::Node pyMongo() { result = API::moduleImport("pymongo").getMember("MongoClient").getReturn() + or + // see https://pymongo.readthedocs.io/en/stable/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient + result = + API::moduleImport("pymongo").getMember("mongo_client").getMember("MongoClient").getReturn() } /** Gets a reference to `flask_pymongo.PyMongo` */ From e58e9a273bd5b4d9aa61f02345fe1c3cff234ffe Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 7 Apr 2022 16:17:12 +0200 Subject: [PATCH 090/171] Python: `mongoClientInstance` refactoring --- .../src/experimental/semmle/python/frameworks/NoSQL.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll index 99681c8502d..bfb350915eb 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll @@ -38,7 +38,7 @@ private module NoSql { * Gets a reference to an initialized `Mongo` instance. * See `pyMongo()`, `flask_PyMongo()` */ - private API::Node mongoInstance() { + private API::Node mongoClientInstance() { result = pyMongo() or result = flask_PyMongo() } @@ -56,17 +56,17 @@ private module NoSql { /** * Gets a reference to a `Mongo` DB use. * - * See `mongoInstance()`, `mongoDBInstance()`. + * See `mongoClientInstance()`, `mongoDBInstance()`. */ private DataFlow::LocalSourceNode mongoDB(DataFlow::TypeTracker t) { t.start() and ( exists(SubscriptNode subscript | - subscript.getObject() = mongoInstance().getAUse().asCfgNode() and + subscript.getObject() = mongoClientInstance().getAUse().asCfgNode() and result.asCfgNode() = subscript ) or - result.(DataFlow::AttrRead).getObject() = mongoInstance().getAUse() + result.(DataFlow::AttrRead).getObject() = mongoClientInstance().getAUse() or result = mongoDBInstance().getAUse() ) From 7ca19653dfd3242da06820e56392c8d5da2ee600 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 7 Apr 2022 16:22:57 +0200 Subject: [PATCH 091/171] Python: `mongoDBInstance` refactor --- .../semmle/python/frameworks/NoSQL.qll | 34 +++++++------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll index bfb350915eb..1fd1075b7d4 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll @@ -44,21 +44,9 @@ private module NoSql { } /** - * Gets a reference to an initialized `Mongo` DB instance. - * See `mongoEngine()`, `flask_MongoEngine()` + * Gets a reference to a `Mongo` DB instance. */ - private API::Node mongoDBInstance() { - result = mongoEngine().getMember(["get_db", "connect"]).getReturn() or - result = mongoEngine().getMember("connection").getMember(["get_db", "connect"]).getReturn() or - result = flask_MongoEngine().getMember("get_db").getReturn() - } - - /** - * Gets a reference to a `Mongo` DB use. - * - * See `mongoClientInstance()`, `mongoDBInstance()`. - */ - private DataFlow::LocalSourceNode mongoDB(DataFlow::TypeTracker t) { + private DataFlow::LocalSourceNode mongoDBInstance(DataFlow::TypeTracker t) { t.start() and ( exists(SubscriptNode subscript | @@ -68,10 +56,14 @@ private module NoSql { or result.(DataFlow::AttrRead).getObject() = mongoClientInstance().getAUse() or - result = mongoDBInstance().getAUse() + result = mongoEngine().getMember(["get_db", "connect"]).getACall() + or + result = mongoEngine().getMember("connection").getMember(["get_db", "connect"]).getACall() + or + result = flask_MongoEngine().getMember("get_db").getACall() ) or - exists(DataFlow::TypeTracker t2 | result = mongoDB(t2).track(t2, t)) + exists(DataFlow::TypeTracker t2 | result = mongoDBInstance(t2).track(t2, t)) } /** @@ -85,21 +77,21 @@ private module NoSql { * * `mongo.db` would be a use of a `Mongo` instance, and so the result. */ - private DataFlow::Node mongoDB() { mongoDB(DataFlow::TypeTracker::end()).flowsTo(result) } + private DataFlow::Node mongoDBInstance() { + mongoDBInstance(DataFlow::TypeTracker::end()).flowsTo(result) + } /** * Gets a reference to a `Mongo` collection use. - * - * See `mongoDB()`. */ private DataFlow::LocalSourceNode mongoCollection(DataFlow::TypeTracker t) { t.start() and ( exists(SubscriptNode subscript | result.asCfgNode() = subscript | - subscript.getObject() = mongoDB().asCfgNode() + subscript.getObject() = mongoDBInstance().asCfgNode() ) or - result.(DataFlow::AttrRead).getObject() = mongoDB() + result.(DataFlow::AttrRead).getObject() = mongoDBInstance() ) or exists(DataFlow::TypeTracker t2 | result = mongoCollection(t2).track(t2, t)) From 89eeaf85d50d487a81c464b10a63372c21389e89 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 7 Apr 2022 16:24:21 +0200 Subject: [PATCH 092/171] Python: Handle `get_database` on `MongoClient` instance --- .../experimental/semmle/python/frameworks/NoSQL.qll | 4 ++++ .../Security/CWE-943/NoSQLInjection.expected | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll index 1fd1075b7d4..1be6cc6f74b 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll @@ -61,6 +61,10 @@ private module NoSql { result = mongoEngine().getMember("connection").getMember(["get_db", "connect"]).getACall() or result = flask_MongoEngine().getMember("get_db").getACall() + or + // see https://pymongo.readthedocs.io/en/stable/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient.get_default_database + // see https://pymongo.readthedocs.io/en/stable/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient.get_database + result = mongoClientInstance().getMember(["get_default_database", "get_database"]).getACall() ) or exists(DataFlow::TypeTracker t2 | result = mongoDBInstance(t2).track(t2, t)) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected index c39aea2345d..677d21b69e7 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected @@ -53,6 +53,10 @@ edges | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | pymongo_test.py:29:27:29:38 | ControlFlowNode for Attribute | | pymongo_test.py:29:27:29:38 | ControlFlowNode for Attribute | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | +| pymongo_test.py:38:16:38:51 | ControlFlowNode for Attribute() | pymongo_test.py:42:34:42:73 | ControlFlowNode for Dict | +| pymongo_test.py:38:27:38:33 | ControlFlowNode for request | pymongo_test.py:38:27:38:38 | ControlFlowNode for Attribute | +| pymongo_test.py:38:27:38:38 | ControlFlowNode for Attribute | pymongo_test.py:38:27:38:50 | ControlFlowNode for Subscript | +| pymongo_test.py:38:27:38:50 | ControlFlowNode for Subscript | pymongo_test.py:38:16:38:51 | ControlFlowNode for Attribute() | nodes | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | flask_mongoengine_bad.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | @@ -119,6 +123,11 @@ nodes | pymongo_test.py:29:27:29:38 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| pymongo_test.py:38:16:38:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| pymongo_test.py:38:27:38:33 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| pymongo_test.py:38:27:38:38 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| pymongo_test.py:38:27:38:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| pymongo_test.py:42:34:42:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | subpaths #select | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | This | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | user-provided value | @@ -132,3 +141,4 @@ subpaths | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | This | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | user-provided value | | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | This | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | user-provided value | | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | This | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | user-provided value | +| pymongo_test.py:42:34:42:73 | ControlFlowNode for Dict | pymongo_test.py:38:27:38:33 | ControlFlowNode for request | pymongo_test.py:42:34:42:73 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_test.py:42:34:42:73 | ControlFlowNode for Dict | This | pymongo_test.py:38:27:38:33 | ControlFlowNode for request | user-provided value | From ec66f26ade803c7d999dd852d93f282df1e11b4f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 7 Apr 2022 16:32:20 +0200 Subject: [PATCH 093/171] Python: Handle `get_collection` on pymongo DB --- .../semmle/python/frameworks/NoSQL.qll | 6 ++++++ .../Security/CWE-943/NoSQLInjection.expected | 20 +++++++++---------- .../Security/CWE-943/pymongo_test.py | 3 ++- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll index 1be6cc6f74b..fa135009ed0 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll @@ -96,6 +96,12 @@ private module NoSql { ) or result.(DataFlow::AttrRead).getObject() = mongoDBInstance() + or + // see https://pymongo.readthedocs.io/en/stable/api/pymongo/database.html#pymongo.database.Database.get_collection + // see https://pymongo.readthedocs.io/en/stable/api/pymongo/database.html#pymongo.database.Database.create_collection + result + .(DataFlow::MethodCallNode) + .calls(mongoDBInstance(), ["get_collection", "create_collection"]) ) or exists(DataFlow::TypeTracker t2 | result = mongoCollection(t2).track(t2, t)) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected index 677d21b69e7..2922cc9f97e 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected @@ -53,10 +53,10 @@ edges | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | pymongo_test.py:29:27:29:38 | ControlFlowNode for Attribute | | pymongo_test.py:29:27:29:38 | ControlFlowNode for Attribute | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | -| pymongo_test.py:38:16:38:51 | ControlFlowNode for Attribute() | pymongo_test.py:42:34:42:73 | ControlFlowNode for Dict | -| pymongo_test.py:38:27:38:33 | ControlFlowNode for request | pymongo_test.py:38:27:38:38 | ControlFlowNode for Attribute | -| pymongo_test.py:38:27:38:38 | ControlFlowNode for Attribute | pymongo_test.py:38:27:38:50 | ControlFlowNode for Subscript | -| pymongo_test.py:38:27:38:50 | ControlFlowNode for Subscript | pymongo_test.py:38:16:38:51 | ControlFlowNode for Attribute() | +| pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | +| pymongo_test.py:39:27:39:33 | ControlFlowNode for request | pymongo_test.py:39:27:39:38 | ControlFlowNode for Attribute | +| pymongo_test.py:39:27:39:38 | ControlFlowNode for Attribute | pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | +| pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | nodes | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | flask_mongoengine_bad.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | @@ -123,11 +123,11 @@ nodes | pymongo_test.py:29:27:29:38 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:38:16:38:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| pymongo_test.py:38:27:38:33 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| pymongo_test.py:38:27:38:38 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| pymongo_test.py:38:27:38:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| pymongo_test.py:42:34:42:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| pymongo_test.py:39:27:39:33 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| pymongo_test.py:39:27:39:38 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | subpaths #select | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | This | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | user-provided value | @@ -141,4 +141,4 @@ subpaths | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | This | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | user-provided value | | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | This | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | user-provided value | | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | This | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | user-provided value | -| pymongo_test.py:42:34:42:73 | ControlFlowNode for Dict | pymongo_test.py:38:27:38:33 | ControlFlowNode for request | pymongo_test.py:42:34:42:73 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_test.py:42:34:42:73 | ControlFlowNode for Dict | This | pymongo_test.py:38:27:38:33 | ControlFlowNode for request | user-provided value | +| pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | pymongo_test.py:39:27:39:33 | ControlFlowNode for request | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | This | pymongo_test.py:39:27:39:33 | ControlFlowNode for request | user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_test.py b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_test.py index 052c1c65d4f..ecf53ec4f9a 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_test.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_test.py @@ -35,10 +35,11 @@ def bad2(): @app.route("/bad3") def bad3(): + # using `get_` methods instead of subscript/attribute lookups event_id = json.loads(request.args['event_id']) client = MongoClient("localhost", 27017, maxPoolSize=50) db = client.get_database(name="localhost") - collection = db['collection'] + collection = db.get_collection("collection") cursor = collection.find_one({"$where": f"this._id == '${event_id}'"}) From 517444b5ff3067a178c57bdda5d523bd8c16316c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 7 Apr 2022 16:42:40 +0200 Subject: [PATCH 094/171] Python: Fix `SimpleXmlRpcServer.expected` --- .../CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.expected b/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.expected index 4a08d61c47a..5f848fb56bb 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.expected @@ -1 +1 @@ -| xmlrpc_server.py:7:10:7:48 | ControlFlowNode for SimpleXMLRPCServer() | SimpleXMLRPCServer is vulnerable to: Billion Laughs, Quadratic Blowup. | +| xmlrpc_server.py:7:10:7:48 | ControlFlowNode for SimpleXMLRPCServer() | SimpleXMLRPCServer is vulnerable to XML bombs | From bc5dc6ad50abf2985198118c1c86ebf79f1c844a Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sun, 10 Apr 2022 18:24:26 +0200 Subject: [PATCH 095/171] Java: Remove TODO comment for `getRuleExpression()` behavior Predicate behavior has been fixed on `main`. --- java/ql/lib/semmle/code/java/Expr.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index 4659d0e78fc..1e6b14fc9e7 100755 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -2151,7 +2151,6 @@ class StmtExpr extends Expr { this = any(ForStmt s).getAnUpdate() or // Only applies to SwitchStmt, but not to SwitchExpr, see JLS 17 section 14.11.2 - // TODO: Possibly redundant depending on how https://github.com/github/codeql/issues/8570 is resolved this = any(SwitchStmt s).getACase().getRuleExpression() or // TODO: Workarounds for https://github.com/github/codeql/issues/3605 From 785dc1af3c49140a7b4e9ad936ecc80d037b0335 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Tue, 12 Apr 2022 21:09:05 +0530 Subject: [PATCH 096/171] Include changes from review --- .../Security/CWE-285/PamAuthorization.ql | 62 ++++-------- .../Security/CWE-285/PamAuthorizationBad.py | 4 +- .../CWE-285/PamAuthorization.expected | 2 +- .../query-tests/Security/CWE-285/bad.py | 95 ------------------ .../query-tests/Security/CWE-285/good.py | 97 ------------------- .../query-tests/Security/CWE-285/pam_test.py | 59 +++++++++++ 6 files changed, 81 insertions(+), 238 deletions(-) delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-285/bad.py delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-285/good.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-285/pam_test.py diff --git a/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql b/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql index e67745cceac..3f11728de4e 100644 --- a/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql +++ b/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql @@ -13,46 +13,24 @@ import semmle.python.ApiGraphs import experimental.semmle.python.Concepts import semmle.python.dataflow.new.TaintTracking -private class LibPam extends API::Node { - LibPam() { - exists( - API::Node cdll, API::Node find_library, API::Node libpam, API::CallNode cdll_call, - API::CallNode find_lib_call, StrConst str - | - API::moduleImport("ctypes").getMember("CDLL") = cdll and - find_library = API::moduleImport("ctypes.util").getMember("find_library") and - cdll_call = cdll.getACall() and - find_lib_call = find_library.getACall() and - DataFlow::localFlow(DataFlow::exprNode(str), find_lib_call.getArg(0)) and - str.getText() = "pam" and - cdll_call.getArg(0) = find_lib_call and - libpam = cdll_call.getReturn() - | - libpam = this - ) - } - - override string toString() { result = "libpam" } -} - -class PamAuthCall extends API::Node { - PamAuthCall() { exists(LibPam pam | pam.getMember("pam_authenticate") = this) } - - override string toString() { result = "pam_authenticate" } -} - -class PamActMgt extends API::Node { - PamActMgt() { exists(LibPam pam | pam.getMember("pam_acct_mgmt") = this) } - - override string toString() { result = "pam_acct_mgmt" } -} - -from PamAuthCall p, API::CallNode u, Expr handle -where - u = p.getACall() and - handle = u.asExpr().(Call).getArg(0) and - not exists(PamActMgt pam | - DataFlow::localFlow(DataFlow::exprNode(handle), - DataFlow::exprNode(pam.getACall().asExpr().(Call).getArg(0))) +API::Node libPam() { + exists(API::CallNode findLibCall, API::CallNode cdllCall, StrConst str | + findLibCall = API::moduleImport("ctypes.util").getMember("find_library").getACall() and + cdllCall = API::moduleImport("ctypes").getMember("CDLL").getACall() and + DataFlow::localFlow(DataFlow::exprNode(str), findLibCall.getArg(0)) and + str.getText() = "pam" and + cdllCall.getArg(0) = findLibCall + | + result = cdllCall.getReturn() ) -select u, "This PAM authentication call may be lead to an authorization bypass." +} + +from API::CallNode authenticateCall, DataFlow::Node handle +where + authenticateCall = libPam().getMember("pam_authenticate").getACall() and + handle = authenticateCall.getArg(0) and + not exists(API::CallNode acctMgmtCall | + acctMgmtCall = libPam().getMember("pam_acct_mgmt").getACall() and + DataFlow::localFlow(handle, acctMgmtCall.getArg(0)) + ) +select authenticateCall, "This PAM authentication call may be lead to an authorization bypass." diff --git a/python/ql/src/experimental/Security/CWE-285/PamAuthorizationBad.py b/python/ql/src/experimental/Security/CWE-285/PamAuthorizationBad.py index 3b06156f551..257f9b99729 100644 --- a/python/ql/src/experimental/Security/CWE-285/PamAuthorizationBad.py +++ b/python/ql/src/experimental/Security/CWE-285/PamAuthorizationBad.py @@ -1,11 +1,9 @@ def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True): libpam = CDLL(find_library("pam")) pam_authenticate = libpam.pam_authenticate - pam_acct_mgmt = libpam.pam_acct_mgmt pam_authenticate.restype = c_int pam_authenticate.argtypes = [PamHandle, c_int] - pam_acct_mgmt.restype = c_int - pam_acct_mgmt.argtypes = [PamHandle, c_int] + handle = PamHandle() conv = PamConv(my_conv, 0) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected b/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected index 52c4c8ac669..cde7271874a 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected @@ -1 +1 @@ -| bad.py:92:18:92:44 | ControlFlowNode for pam_authenticate() | This PAM authentication call may be lead to an authorization bypass. | +| pam_test.py:44:18:44:44 | ControlFlowNode for pam_authenticate() | This PAM authentication call may be lead to an authorization bypass. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-285/bad.py b/python/ql/test/experimental/query-tests/Security/CWE-285/bad.py deleted file mode 100644 index 84527d6f6fb..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-285/bad.py +++ /dev/null @@ -1,95 +0,0 @@ -from ctypes import CDLL, POINTER, Structure, CFUNCTYPE, cast, byref, sizeof -from ctypes import c_void_p, c_size_t, c_char_p, c_char, c_int -from ctypes import memmove -from ctypes.util import find_library - -class PamHandle(Structure): - _fields_ = [ ("handle", c_void_p) ] - - def __init__(self): - Structure.__init__(self) - self.handle = 0 - -class PamMessage(Structure): - """wrapper class for pam_message structure""" - _fields_ = [ ("msg_style", c_int), ("msg", c_char_p) ] - - def __repr__(self): - return "" % (self.msg_style, self.msg) - -class PamResponse(Structure): - """wrapper class for pam_response structure""" - _fields_ = [ ("resp", c_char_p), ("resp_retcode", c_int) ] - - def __repr__(self): - return "" % (self.resp_retcode, self.resp) - -conv_func = CFUNCTYPE(c_int, c_int, POINTER(POINTER(PamMessage)), POINTER(POINTER(PamResponse)), c_void_p) - -class PamConv(Structure): - """wrapper class for pam_conv structure""" - _fields_ = [ ("conv", conv_func), ("appdata_ptr", c_void_p) ] - -# Various constants -PAM_PROMPT_ECHO_OFF = 1 -PAM_PROMPT_ECHO_ON = 2 -PAM_ERROR_MSG = 3 -PAM_TEXT_INFO = 4 -PAM_REINITIALIZE_CRED = 8 - -libc = CDLL(find_library("c")) -libpam = CDLL(find_library("pam")) - -calloc = libc.calloc -calloc.restype = c_void_p -calloc.argtypes = [c_size_t, c_size_t] - -# bug #6 (@NIPE-SYSTEMS), some libpam versions don't include this function -if hasattr(libpam, 'pam_end'): - pam_end = libpam.pam_end - pam_end.restype = c_int - pam_end.argtypes = [PamHandle, c_int] - -pam_start = libpam.pam_start -pam_start.restype = c_int -pam_start.argtypes = [c_char_p, c_char_p, POINTER(PamConv), POINTER(PamHandle)] - -pam_setcred = libpam.pam_setcred -pam_setcred.restype = c_int -pam_setcred.argtypes = [PamHandle, c_int] - -pam_strerror = libpam.pam_strerror -pam_strerror.restype = c_char_p -pam_strerror.argtypes = [PamHandle, c_int] - -pam_authenticate = libpam.pam_authenticate -pam_authenticate.restype = c_int -pam_authenticate.argtypes = [PamHandle, c_int] - -pam_acct_mgmt = libpam.pam_acct_mgmt -pam_acct_mgmt.restype = c_int -pam_acct_mgmt.argtypes = [PamHandle, c_int] - -class pam(): - code = 0 - reason = None - - def __init__(self): - pass - - def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True): - @conv_func - def my_conv(n_messages, messages, p_response, app_data): - return 0 - - - cpassword = c_char_p(password) - - handle = PamHandle() - conv = PamConv(my_conv, 0) - retval = pam_start(service, username, byref(conv), byref(handle)) - - retval = pam_authenticate(handle, 0) - auth_success = retval == 0 - - return auth_success \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/Security/CWE-285/good.py b/python/ql/test/experimental/query-tests/Security/CWE-285/good.py deleted file mode 100644 index e9996c770ed..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-285/good.py +++ /dev/null @@ -1,97 +0,0 @@ -from ctypes import CDLL, POINTER, Structure, CFUNCTYPE, cast, byref, sizeof -from ctypes import c_void_p, c_size_t, c_char_p, c_char, c_int -from ctypes import memmove -from ctypes.util import find_library - -class PamHandle(Structure): - _fields_ = [ ("handle", c_void_p) ] - - def __init__(self): - Structure.__init__(self) - self.handle = 0 - -class PamMessage(Structure): - """wrapper class for pam_message structure""" - _fields_ = [ ("msg_style", c_int), ("msg", c_char_p) ] - - def __repr__(self): - return "" % (self.msg_style, self.msg) - -class PamResponse(Structure): - """wrapper class for pam_response structure""" - _fields_ = [ ("resp", c_char_p), ("resp_retcode", c_int) ] - - def __repr__(self): - return "" % (self.resp_retcode, self.resp) - -conv_func = CFUNCTYPE(c_int, c_int, POINTER(POINTER(PamMessage)), POINTER(POINTER(PamResponse)), c_void_p) - -class PamConv(Structure): - """wrapper class for pam_conv structure""" - _fields_ = [ ("conv", conv_func), ("appdata_ptr", c_void_p) ] - -# Various constants -PAM_PROMPT_ECHO_OFF = 1 -PAM_PROMPT_ECHO_ON = 2 -PAM_ERROR_MSG = 3 -PAM_TEXT_INFO = 4 -PAM_REINITIALIZE_CRED = 8 - -libc = CDLL(find_library("c")) -libpam = CDLL(find_library("pam")) - -calloc = libc.calloc -calloc.restype = c_void_p -calloc.argtypes = [c_size_t, c_size_t] - -# bug #6 (@NIPE-SYSTEMS), some libpam versions don't include this function -if hasattr(libpam, 'pam_end'): - pam_end = libpam.pam_end - pam_end.restype = c_int - pam_end.argtypes = [PamHandle, c_int] - -pam_start = libpam.pam_start -pam_start.restype = c_int -pam_start.argtypes = [c_char_p, c_char_p, POINTER(PamConv), POINTER(PamHandle)] - -pam_setcred = libpam.pam_setcred -pam_setcred.restype = c_int -pam_setcred.argtypes = [PamHandle, c_int] - -pam_strerror = libpam.pam_strerror -pam_strerror.restype = c_char_p -pam_strerror.argtypes = [PamHandle, c_int] - -pam_authenticate = libpam.pam_authenticate -pam_authenticate.restype = c_int -pam_authenticate.argtypes = [PamHandle, c_int] - -pam_acct_mgmt = libpam.pam_acct_mgmt -pam_acct_mgmt.restype = c_int -pam_acct_mgmt.argtypes = [PamHandle, c_int] - -class pam(): - code = 0 - reason = None - - def __init__(self): - pass - - def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True): - @conv_func - def my_conv(n_messages, messages, p_response, app_data): - return 0 - - - cpassword = c_char_p(password) - - handle = PamHandle() - conv = PamConv(my_conv, 0) - retval = pam_start(service, username, byref(conv), byref(handle)) - - retval = pam_authenticate(handle, 0) - if retval == 0: - retval = pam_acct_mgmt(handle, 0) - auth_success = retval == 0 - - return auth_success \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/Security/CWE-285/pam_test.py b/python/ql/test/experimental/query-tests/Security/CWE-285/pam_test.py new file mode 100644 index 00000000000..60408ade722 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-285/pam_test.py @@ -0,0 +1,59 @@ +from ctypes import CDLL, POINTER, Structure, byref +from ctypes import c_char_p, c_int +from ctypes.util import find_library + + +class PamHandle(Structure): + pass + + +class PamMessage(Structure): + pass + + +class PamResponse(Structure): + pass + + +class PamConv(Structure): + pass + + +libpam = CDLL(find_library("pam")) + +pam_start = libpam.pam_start +pam_start.restype = c_int +pam_start.argtypes = [c_char_p, c_char_p, POINTER(PamConv), POINTER(PamHandle)] + +pam_authenticate = libpam.pam_authenticate +pam_authenticate.restype = c_int +pam_authenticate.argtypes = [PamHandle, c_int] + +pam_acct_mgmt = libpam.pam_acct_mgmt +pam_acct_mgmt.restype = c_int +pam_acct_mgmt.argtypes = [PamHandle, c_int] + + +class pam(): + + def authenticate_bad(self, username, service='login'): + handle = PamHandle() + conv = PamConv(None, 0) + retval = pam_start(service, username, byref(conv), byref(handle)) + + retval = pam_authenticate(handle, 0) + auth_success = retval == 0 + + return auth_success + + def authenticate_good(self, username, service='login'): + handle = PamHandle() + conv = PamConv(None, 0) + retval = pam_start(service, username, byref(conv), byref(handle)) + + retval = pam_authenticate(handle, 0) + if retval == 0: + retval = pam_acct_mgmt(handle, 0) + auth_success = retval == 0 + + return auth_success From 6235dc503965deafd3f30ff76e3c7fcd2d5fceb6 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 13 Apr 2022 11:44:15 +0200 Subject: [PATCH 097/171] Python: Handle `find_library` assignment to temp variable --- .../src/experimental/Security/CWE-285/PamAuthorization.ql | 7 +++---- .../query-tests/Security/CWE-285/PamAuthorization.expected | 2 +- .../experimental/query-tests/Security/CWE-285/pam_test.py | 6 +++++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql b/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql index 3f11728de4e..595d1af13a4 100644 --- a/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql +++ b/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql @@ -14,12 +14,11 @@ import experimental.semmle.python.Concepts import semmle.python.dataflow.new.TaintTracking API::Node libPam() { - exists(API::CallNode findLibCall, API::CallNode cdllCall, StrConst str | + exists(API::CallNode findLibCall, API::CallNode cdllCall | findLibCall = API::moduleImport("ctypes.util").getMember("find_library").getACall() and + findLibCall.getParameter(0).getAValueReachingRhs().asExpr().(StrConst).getText() = "pam" and cdllCall = API::moduleImport("ctypes").getMember("CDLL").getACall() and - DataFlow::localFlow(DataFlow::exprNode(str), findLibCall.getArg(0)) and - str.getText() = "pam" and - cdllCall.getArg(0) = findLibCall + cdllCall.getParameter(0).getAValueReachingRhs() = findLibCall | result = cdllCall.getReturn() ) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected b/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected index cde7271874a..1b6c23291be 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-285/PamAuthorization.expected @@ -1 +1 @@ -| pam_test.py:44:18:44:44 | ControlFlowNode for pam_authenticate() | This PAM authentication call may be lead to an authorization bypass. | +| pam_test.py:48:18:48:44 | ControlFlowNode for pam_authenticate() | This PAM authentication call may be lead to an authorization bypass. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-285/pam_test.py b/python/ql/test/experimental/query-tests/Security/CWE-285/pam_test.py index 60408ade722..966e13cb991 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-285/pam_test.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-285/pam_test.py @@ -18,9 +18,13 @@ class PamResponse(Structure): class PamConv(Structure): pass - +# this is normal way to do things libpam = CDLL(find_library("pam")) +# but we also handle assignment to temp variable +temp = find_library("pam") +libpam = CDLL(temp) + pam_start = libpam.pam_start pam_start.restype = c_int pam_start.argtypes = [c_char_p, c_char_p, POINTER(PamConv), POINTER(PamHandle)] From 40da7a10553c76ad98bb0f6c6a5af652fc3f4e5e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 21 Apr 2022 16:55:50 +0100 Subject: [PATCH 098/171] C++: Add a test of NoCheckBeforeUnsafePutUser.ql. --- .../NoCheckBeforeUnsafePutUser.expected | 1 + .../NoCheckBeforeUnsafePutUser.qlref | 1 + .../NoCheckBeforeUnsafePutUser/test.cpp | 82 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.expected create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.qlref create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/test.cpp diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.expected new file mode 100644 index 00000000000..ffb7941f1cd --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.expected @@ -0,0 +1 @@ +| test.cpp:14:16:14:16 | p | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:14:16:14:16 | p | p | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.qlref new file mode 100644 index 00000000000..a4543b332dd --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/test.cpp new file mode 100644 index 00000000000..755a73864c7 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/test.cpp @@ -0,0 +1,82 @@ + +typedef unsigned long size_t; + +void SYSC_SOMESYSTEMCALL(void *param); + +bool user_access_begin_impl(const void *where, size_t sz); +void user_access_end_impl(); +#define user_access_begin(where, sz) user_access_begin_impl(where, sz) +#define user_access_end() user_access_end_impl() + +void unsafe_put_user_impl(int what, const void *where, size_t sz); +#define unsafe_put_user(what, where) unsafe_put_user_impl( (what), (where), sizeof(*(where)) ) + +void test1(int p) +{ + SYSC_SOMESYSTEMCALL(&p); + + unsafe_put_user(123, &p); // BAD +} + +void test2(int p) +{ + SYSC_SOMESYSTEMCALL(&p); + + if (user_access_begin(&p, sizeof(p))) + { + unsafe_put_user(123, &p); // GOOD + + user_access_end(); + } +} + +void test3() +{ + int v; + + SYSC_SOMESYSTEMCALL(&v); + + unsafe_put_user(123, &v); // BAD [NOT DETECTED] +} + +void test4() +{ + int v; + + SYSC_SOMESYSTEMCALL(&v); + + if (user_access_begin(&v, sizeof(v))) + { + unsafe_put_user(123, &v); // GOOD + + user_access_end(); + } +} + +struct data +{ + int x; +}; + +void test5() +{ + data myData; + + SYSC_SOMESYSTEMCALL(&myData); + + unsafe_put_user(123, &(myData.x)); // BAD [NOT DETECTED] +} + +void test6() +{ + data myData; + + SYSC_SOMESYSTEMCALL(&myData); + + if (user_access_begin(&myData, sizeof(myData))) + { + unsafe_put_user(123, &(myData.x)); // GOOD + + user_access_end(); + } +} From 7359ffaa2ea1be1aa45bb7957fdcacf9b8eb73c5 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Thu, 28 Apr 2022 11:36:01 +0200 Subject: [PATCH 099/171] Ruby: add tree-sitter test case --- .../library-tests/ast/TreeSitter.expected | 5846 +++++++++++++++++ ruby/ql/test/library-tests/ast/TreeSitter.ql | 31 + 2 files changed, 5877 insertions(+) create mode 100644 ruby/ql/test/library-tests/ast/TreeSitter.expected create mode 100644 ruby/ql/test/library-tests/ast/TreeSitter.ql diff --git a/ruby/ql/test/library-tests/ast/TreeSitter.expected b/ruby/ql/test/library-tests/ast/TreeSitter.expected new file mode 100644 index 00000000000..ecf00e54895 --- /dev/null +++ b/ruby/ql/test/library-tests/ast/TreeSitter.expected @@ -0,0 +1,5846 @@ +calls/calls.rb: +# 1| [Program] Program +# 2| 0: [Call] Call +# 2| 0: [Identifier] foo +# 2| 1: [ArgumentList] ArgumentList +# 2| 0: [ReservedWord] ( +# 2| 1: [ReservedWord] ) +# 5| 1: [Call] Call +# 5| 0: [ScopeResolution] ScopeResolution +# 5| 0: [Constant] Foo +# 5| 1: [ReservedWord] :: +# 5| 2: [Identifier] bar +# 5| 1: [ArgumentList] ArgumentList +# 5| 0: [ReservedWord] ( +# 5| 1: [ReservedWord] ) +# 8| 2: [Call] Call +# 8| 0: [ScopeResolution] ScopeResolution +# 8| 0: [ReservedWord] :: +# 8| 1: [Identifier] bar +# 8| 1: [ArgumentList] ArgumentList +# 8| 0: [ReservedWord] ( +# 8| 1: [ReservedWord] ) +# 11| 3: [Call] Call +# 11| 0: [Integer] 123 +# 11| 1: [ReservedWord] . +# 11| 2: [Identifier] bar +# 14| 4: [Call] Call +# 14| 0: [Identifier] foo +# 14| 1: [ArgumentList] ArgumentList +# 14| 0: [Integer] 0 +# 14| 1: [ReservedWord] , +# 14| 2: [Integer] 1 +# 14| 3: [ReservedWord] , +# 14| 4: [Integer] 2 +# 17| 5: [Call] Call +# 17| 0: [Identifier] foo +# 17| 1: [Block] Block +# 17| 0: [ReservedWord] { +# 17| 1: [BlockParameters] BlockParameters +# 17| 0: [ReservedWord] | +# 17| 1: [Identifier] x +# 17| 2: [ReservedWord] | +# 17| 2: [Binary] Binary +# 17| 0: [Identifier] x +# 17| 1: [ReservedWord] + +# 17| 2: [Integer] 1 +# 17| 3: [ReservedWord] } +# 20| 6: [Call] Call +# 20| 0: [Identifier] foo +# 20| 1: [DoBlock] DoBlock +# 20| 0: [ReservedWord] do +# 20| 1: [BlockParameters] BlockParameters +# 20| 0: [ReservedWord] | +# 20| 1: [Identifier] x +# 20| 2: [ReservedWord] | +# 21| 2: [Binary] Binary +# 21| 0: [Identifier] x +# 21| 1: [ReservedWord] + +# 21| 2: [Integer] 1 +# 22| 3: [ReservedWord] end +# 25| 7: [Call] Call +# 25| 0: [Integer] 123 +# 25| 1: [ReservedWord] . +# 25| 2: [Identifier] bar +# 25| 3: [ArgumentList] ArgumentList +# 25| 0: [ReservedWord] ( +# 25| 1: [String] String +# 25| 0: [ReservedWord] ' +# 25| 1: [StringContent] foo +# 25| 2: [ReservedWord] ' +# 25| 2: [ReservedWord] ) +# 25| 4: [DoBlock] DoBlock +# 25| 0: [ReservedWord] do +# 25| 1: [BlockParameters] BlockParameters +# 25| 0: [ReservedWord] | +# 25| 1: [Identifier] x +# 25| 2: [ReservedWord] | +# 26| 2: [Binary] Binary +# 26| 0: [Identifier] x +# 26| 1: [ReservedWord] + +# 26| 2: [Integer] 1 +# 27| 3: [ReservedWord] end +# 30| 8: [Method] Method +# 30| 0: [ReservedWord] def +# 30| 1: [Identifier] method_that_yields +# 31| 2: [Yield] Yield +# 31| 0: [ReservedWord] yield +# 32| 3: [ReservedWord] end +# 35| 9: [Method] Method +# 35| 0: [ReservedWord] def +# 35| 1: [Identifier] another_method_that_yields +# 36| 2: [Yield] Yield +# 36| 0: [ReservedWord] yield +# 36| 1: [ArgumentList] ArgumentList +# 36| 0: [Integer] 100 +# 36| 1: [ReservedWord] , +# 36| 2: [Integer] 200 +# 37| 3: [ReservedWord] end +# 46| 10: [Identifier] foo +# 47| 11: [ScopeResolution] ScopeResolution +# 47| 0: [Constant] X +# 47| 1: [ReservedWord] :: +# 47| 2: [Identifier] foo +# 50| 12: [ParenthesizedStatements] ParenthesizedStatements +# 50| 0: [ReservedWord] ( +# 50| 1: [Identifier] foo +# 50| 2: [ReservedWord] ) +# 51| 13: [ParenthesizedStatements] ParenthesizedStatements +# 51| 0: [ReservedWord] ( +# 51| 1: [ScopeResolution] ScopeResolution +# 51| 0: [Constant] X +# 51| 1: [ReservedWord] :: +# 51| 2: [Identifier] foo +# 51| 2: [ReservedWord] ) +# 54| 14: [Call] Call +# 54| 0: [Identifier] some_func +# 54| 1: [ArgumentList] ArgumentList +# 54| 0: [ReservedWord] ( +# 54| 1: [Identifier] foo +# 54| 2: [ReservedWord] ) +# 55| 15: [Call] Call +# 55| 0: [Identifier] some_func +# 55| 1: [ArgumentList] ArgumentList +# 55| 0: [ReservedWord] ( +# 55| 1: [ScopeResolution] ScopeResolution +# 55| 0: [Constant] X +# 55| 1: [ReservedWord] :: +# 55| 2: [Identifier] foo +# 55| 2: [ReservedWord] ) +# 58| 16: [Array] Array +# 58| 0: [ReservedWord] [ +# 58| 1: [Identifier] foo +# 58| 2: [ReservedWord] ] +# 59| 17: [Array] Array +# 59| 0: [ReservedWord] [ +# 59| 1: [ScopeResolution] ScopeResolution +# 59| 0: [Constant] X +# 59| 1: [ReservedWord] :: +# 59| 2: [Identifier] foo +# 59| 2: [ReservedWord] ] +# 62| 18: [Assignment] Assignment +# 62| 0: [Identifier] var1 +# 62| 1: [ReservedWord] = +# 62| 2: [Identifier] foo +# 63| 19: [Assignment] Assignment +# 63| 0: [Identifier] var1 +# 63| 1: [ReservedWord] = +# 63| 2: [ScopeResolution] ScopeResolution +# 63| 0: [Constant] X +# 63| 1: [ReservedWord] :: +# 63| 2: [Identifier] foo +# 66| 20: [OperatorAssignment] OperatorAssignment +# 66| 0: [Identifier] var1 +# 66| 1: [ReservedWord] += +# 66| 2: [Identifier] bar +# 67| 21: [OperatorAssignment] OperatorAssignment +# 67| 0: [Identifier] var1 +# 67| 1: [ReservedWord] += +# 67| 2: [ScopeResolution] ScopeResolution +# 67| 0: [Constant] X +# 67| 1: [ReservedWord] :: +# 67| 2: [Identifier] bar +# 70| 22: [Assignment] Assignment +# 70| 0: [Identifier] var1 +# 70| 1: [ReservedWord] = +# 70| 2: [RightAssignmentList] RightAssignmentList +# 70| 0: [Identifier] foo +# 70| 1: [ReservedWord] , +# 70| 2: [ScopeResolution] ScopeResolution +# 70| 0: [Constant] X +# 70| 1: [ReservedWord] :: +# 70| 2: [Identifier] bar +# 73| 23: [Begin] Begin +# 73| 0: [ReservedWord] begin +# 74| 1: [Identifier] foo +# 75| 2: [ScopeResolution] ScopeResolution +# 75| 0: [Constant] X +# 75| 1: [ReservedWord] :: +# 75| 2: [Identifier] foo +# 76| 3: [ReservedWord] end +# 79| 24: [BeginBlock] BeginBlock +# 79| 0: [ReservedWord] BEGIN +# 79| 1: [ReservedWord] { +# 79| 2: [Identifier] foo +# 79| 3: [ReservedWord] ; +# 79| 4: [ScopeResolution] ScopeResolution +# 79| 0: [Constant] X +# 79| 1: [ReservedWord] :: +# 79| 2: [Identifier] bar +# 79| 5: [ReservedWord] } +# 82| 25: [EndBlock] EndBlock +# 82| 0: [ReservedWord] END +# 82| 1: [ReservedWord] { +# 82| 2: [Identifier] foo +# 82| 3: [ReservedWord] ; +# 82| 4: [ScopeResolution] ScopeResolution +# 82| 0: [Constant] X +# 82| 1: [ReservedWord] :: +# 82| 2: [Identifier] bar +# 82| 5: [ReservedWord] } +# 85| 26: [Binary] Binary +# 85| 0: [Identifier] foo +# 85| 1: [ReservedWord] + +# 85| 2: [ScopeResolution] ScopeResolution +# 85| 0: [Constant] X +# 85| 1: [ReservedWord] :: +# 85| 2: [Identifier] bar +# 88| 27: [Unary] Unary +# 88| 0: [ReservedWord] ! +# 88| 1: [Identifier] foo +# 89| 28: [Unary] Unary +# 89| 0: [ReservedWord] ~ +# 89| 1: [ScopeResolution] ScopeResolution +# 89| 0: [Constant] X +# 89| 1: [ReservedWord] :: +# 89| 2: [Identifier] bar +# 92| 29: [Call] Call +# 92| 0: [Identifier] foo +# 92| 1: [ArgumentList] ArgumentList +# 92| 0: [ReservedWord] ( +# 92| 1: [ReservedWord] ) +# 92| 2: [Block] Block +# 92| 0: [ReservedWord] { +# 92| 1: [Identifier] bar +# 92| 2: [ReservedWord] ; +# 92| 3: [ScopeResolution] ScopeResolution +# 92| 0: [Constant] X +# 92| 1: [ReservedWord] :: +# 92| 2: [Identifier] baz +# 92| 4: [ReservedWord] } +# 95| 30: [Call] Call +# 95| 0: [Identifier] foo +# 95| 1: [ArgumentList] ArgumentList +# 95| 0: [ReservedWord] ( +# 95| 1: [ReservedWord] ) +# 95| 2: [DoBlock] DoBlock +# 95| 0: [ReservedWord] do +# 96| 1: [Identifier] bar +# 97| 2: [ScopeResolution] ScopeResolution +# 97| 0: [Constant] X +# 97| 1: [ReservedWord] :: +# 97| 2: [Identifier] baz +# 98| 3: [ReservedWord] end +# 101| 31: [Call] Call +# 101| 0: [Identifier] foo +# 101| 1: [ReservedWord] . +# 101| 2: [Identifier] bar +# 101| 3: [ArgumentList] ArgumentList +# 101| 0: [ReservedWord] ( +# 101| 1: [ReservedWord] ) +# 102| 32: [Call] Call +# 102| 0: [Identifier] bar +# 102| 1: [ReservedWord] . +# 102| 2: [Identifier] baz +# 102| 3: [ArgumentList] ArgumentList +# 102| 0: [ReservedWord] ( +# 102| 1: [ReservedWord] ) +# 106| 33: [Case] Case +# 106| 0: [ReservedWord] case +# 106| 1: [Identifier] foo +# 107| 2: [When] When +# 107| 0: [ReservedWord] when +# 107| 1: [Pattern] Pattern +# 107| 0: [Identifier] bar +# 107| 2: [Then] Then +# 108| 0: [Identifier] baz +# 109| 3: [ReservedWord] end +# 110| 34: [Case] Case +# 110| 0: [ReservedWord] case +# 110| 1: [ScopeResolution] ScopeResolution +# 110| 0: [Constant] X +# 110| 1: [ReservedWord] :: +# 110| 2: [Identifier] foo +# 111| 2: [When] When +# 111| 0: [ReservedWord] when +# 111| 1: [Pattern] Pattern +# 111| 0: [ScopeResolution] ScopeResolution +# 111| 0: [Constant] X +# 111| 1: [ReservedWord] :: +# 111| 2: [Identifier] bar +# 111| 2: [Then] Then +# 112| 0: [ScopeResolution] ScopeResolution +# 112| 0: [Constant] X +# 112| 1: [ReservedWord] :: +# 112| 2: [Identifier] baz +# 113| 3: [ReservedWord] end +# 116| 35: [Class] Class +# 116| 0: [ReservedWord] class +# 116| 1: [Constant] MyClass +# 117| 2: [Identifier] foo +# 118| 3: [ScopeResolution] ScopeResolution +# 118| 0: [Constant] X +# 118| 1: [ReservedWord] :: +# 118| 2: [Identifier] bar +# 119| 4: [ReservedWord] end +# 122| 36: [Class] Class +# 122| 0: [ReservedWord] class +# 122| 1: [Constant] MyClass +# 122| 2: [Superclass] Superclass +# 122| 0: [ReservedWord] < +# 122| 1: [Identifier] foo +# 123| 3: [ReservedWord] end +# 124| 37: [Class] Class +# 124| 0: [ReservedWord] class +# 124| 1: [Constant] MyClass2 +# 124| 2: [Superclass] Superclass +# 124| 0: [ReservedWord] < +# 124| 1: [ScopeResolution] ScopeResolution +# 124| 0: [Constant] X +# 124| 1: [ReservedWord] :: +# 124| 2: [Identifier] foo +# 125| 3: [ReservedWord] end +# 128| 38: [SingletonClass] SingletonClass +# 128| 0: [ReservedWord] class +# 128| 1: [ReservedWord] << +# 128| 2: [Identifier] foo +# 129| 3: [Identifier] bar +# 130| 4: [ReservedWord] end +# 131| 39: [SingletonClass] SingletonClass +# 131| 0: [ReservedWord] class +# 131| 1: [ReservedWord] << +# 131| 2: [ScopeResolution] ScopeResolution +# 131| 0: [Constant] X +# 131| 1: [ReservedWord] :: +# 131| 2: [Identifier] foo +# 132| 3: [ScopeResolution] ScopeResolution +# 132| 0: [Constant] X +# 132| 1: [ReservedWord] :: +# 132| 2: [Identifier] bar +# 133| 4: [ReservedWord] end +# 136| 40: [Method] Method +# 136| 0: [ReservedWord] def +# 136| 1: [Identifier] some_method +# 137| 2: [Identifier] foo +# 138| 3: [ScopeResolution] ScopeResolution +# 138| 0: [Constant] X +# 138| 1: [ReservedWord] :: +# 138| 2: [Identifier] bar +# 139| 4: [ReservedWord] end +# 142| 41: [SingletonMethod] SingletonMethod +# 142| 0: [ReservedWord] def +# 142| 1: [Identifier] foo +# 142| 2: [ReservedWord] . +# 142| 3: [Identifier] some_method +# 143| 4: [Identifier] bar +# 144| 5: [ScopeResolution] ScopeResolution +# 144| 0: [Constant] X +# 144| 1: [ReservedWord] :: +# 144| 2: [Identifier] baz +# 145| 6: [ReservedWord] end +# 148| 42: [Method] Method +# 148| 0: [ReservedWord] def +# 148| 1: [Identifier] method_with_keyword_param +# 148| 2: [MethodParameters] MethodParameters +# 148| 0: [ReservedWord] ( +# 148| 1: [KeywordParameter] KeywordParameter +# 148| 0: [Identifier] keyword +# 148| 1: [ReservedWord] : +# 148| 2: [Identifier] foo +# 148| 2: [ReservedWord] ) +# 149| 3: [ReservedWord] end +# 150| 43: [Method] Method +# 150| 0: [ReservedWord] def +# 150| 1: [Identifier] method_with_keyword_param2 +# 150| 2: [MethodParameters] MethodParameters +# 150| 0: [ReservedWord] ( +# 150| 1: [KeywordParameter] KeywordParameter +# 150| 0: [Identifier] keyword +# 150| 1: [ReservedWord] : +# 150| 2: [ScopeResolution] ScopeResolution +# 150| 0: [Constant] X +# 150| 1: [ReservedWord] :: +# 150| 2: [Identifier] foo +# 150| 2: [ReservedWord] ) +# 151| 3: [ReservedWord] end +# 154| 44: [Method] Method +# 154| 0: [ReservedWord] def +# 154| 1: [Identifier] method_with_optional_param +# 154| 2: [MethodParameters] MethodParameters +# 154| 0: [ReservedWord] ( +# 154| 1: [OptionalParameter] OptionalParameter +# 154| 0: [Identifier] param +# 154| 1: [ReservedWord] = +# 154| 2: [Identifier] foo +# 154| 2: [ReservedWord] ) +# 155| 3: [ReservedWord] end +# 156| 45: [Method] Method +# 156| 0: [ReservedWord] def +# 156| 1: [Identifier] method_with_optional_param2 +# 156| 2: [MethodParameters] MethodParameters +# 156| 0: [ReservedWord] ( +# 156| 1: [OptionalParameter] OptionalParameter +# 156| 0: [Identifier] param +# 156| 1: [ReservedWord] = +# 156| 2: [ScopeResolution] ScopeResolution +# 156| 0: [Constant] X +# 156| 1: [ReservedWord] :: +# 156| 2: [Identifier] foo +# 156| 2: [ReservedWord] ) +# 157| 3: [ReservedWord] end +# 160| 46: [Module] Module +# 160| 0: [ReservedWord] module +# 160| 1: [Constant] SomeModule +# 161| 2: [Identifier] foo +# 162| 3: [ScopeResolution] ScopeResolution +# 162| 0: [Constant] X +# 162| 1: [ReservedWord] :: +# 162| 2: [Identifier] bar +# 163| 4: [ReservedWord] end +# 166| 47: [Conditional] Conditional +# 166| 0: [Identifier] foo +# 166| 1: [ReservedWord] ? +# 166| 2: [Identifier] bar +# 166| 3: [ReservedWord] : +# 166| 4: [Identifier] baz +# 167| 48: [Conditional] Conditional +# 167| 0: [ScopeResolution] ScopeResolution +# 167| 0: [Constant] X +# 167| 1: [ReservedWord] :: +# 167| 2: [Identifier] foo +# 167| 1: [ReservedWord] ? +# 167| 2: [ScopeResolution] ScopeResolution +# 167| 0: [Constant] X +# 167| 1: [ReservedWord] :: +# 167| 2: [Identifier] bar +# 167| 3: [ReservedWord] : +# 167| 4: [ScopeResolution] ScopeResolution +# 167| 0: [Constant] X +# 167| 1: [ReservedWord] :: +# 167| 2: [Identifier] baz +# 170| 49: [If] If +# 170| 0: [ReservedWord] if +# 170| 1: [Identifier] foo +# 170| 2: [Then] Then +# 171| 0: [Identifier] wibble +# 172| 3: [Elsif] Elsif +# 172| 0: [ReservedWord] elsif +# 172| 1: [Identifier] bar +# 172| 2: [Then] Then +# 173| 0: [Identifier] wobble +# 174| 3: [Else] Else +# 174| 0: [ReservedWord] else +# 175| 1: [Identifier] wabble +# 176| 4: [ReservedWord] end +# 177| 50: [If] If +# 177| 0: [ReservedWord] if +# 177| 1: [ScopeResolution] ScopeResolution +# 177| 0: [Constant] X +# 177| 1: [ReservedWord] :: +# 177| 2: [Identifier] foo +# 177| 2: [Then] Then +# 178| 0: [ScopeResolution] ScopeResolution +# 178| 0: [Constant] X +# 178| 1: [ReservedWord] :: +# 178| 2: [Identifier] wibble +# 179| 3: [Elsif] Elsif +# 179| 0: [ReservedWord] elsif +# 179| 1: [ScopeResolution] ScopeResolution +# 179| 0: [Constant] X +# 179| 1: [ReservedWord] :: +# 179| 2: [Identifier] bar +# 179| 2: [Then] Then +# 180| 0: [ScopeResolution] ScopeResolution +# 180| 0: [Constant] X +# 180| 1: [ReservedWord] :: +# 180| 2: [Identifier] wobble +# 181| 3: [Else] Else +# 181| 0: [ReservedWord] else +# 182| 1: [ScopeResolution] ScopeResolution +# 182| 0: [Constant] X +# 182| 1: [ReservedWord] :: +# 182| 2: [Identifier] wabble +# 183| 4: [ReservedWord] end +# 186| 51: [IfModifier] IfModifier +# 186| 0: [Identifier] bar +# 186| 1: [ReservedWord] if +# 186| 2: [Identifier] foo +# 187| 52: [IfModifier] IfModifier +# 187| 0: [ScopeResolution] ScopeResolution +# 187| 0: [Constant] X +# 187| 1: [ReservedWord] :: +# 187| 2: [Identifier] bar +# 187| 1: [ReservedWord] if +# 187| 2: [ScopeResolution] ScopeResolution +# 187| 0: [Constant] X +# 187| 1: [ReservedWord] :: +# 187| 2: [Identifier] foo +# 190| 53: [Unless] Unless +# 190| 0: [ReservedWord] unless +# 190| 1: [Identifier] foo +# 190| 2: [Then] Then +# 191| 0: [Identifier] bar +# 192| 3: [ReservedWord] end +# 193| 54: [Unless] Unless +# 193| 0: [ReservedWord] unless +# 193| 1: [ScopeResolution] ScopeResolution +# 193| 0: [Constant] X +# 193| 1: [ReservedWord] :: +# 193| 2: [Identifier] foo +# 193| 2: [Then] Then +# 194| 0: [ScopeResolution] ScopeResolution +# 194| 0: [Constant] X +# 194| 1: [ReservedWord] :: +# 194| 2: [Identifier] bar +# 195| 3: [ReservedWord] end +# 198| 55: [UnlessModifier] UnlessModifier +# 198| 0: [Identifier] bar +# 198| 1: [ReservedWord] unless +# 198| 2: [Identifier] foo +# 199| 56: [UnlessModifier] UnlessModifier +# 199| 0: [ScopeResolution] ScopeResolution +# 199| 0: [Constant] X +# 199| 1: [ReservedWord] :: +# 199| 2: [Identifier] bar +# 199| 1: [ReservedWord] unless +# 199| 2: [ScopeResolution] ScopeResolution +# 199| 0: [Constant] X +# 199| 1: [ReservedWord] :: +# 199| 2: [Identifier] foo +# 202| 57: [While] While +# 202| 0: [ReservedWord] while +# 202| 1: [Identifier] foo +# 202| 2: [Do] Do +# 202| 0: [ReservedWord] do +# 203| 1: [Identifier] bar +# 204| 2: [ReservedWord] end +# 205| 58: [While] While +# 205| 0: [ReservedWord] while +# 205| 1: [ScopeResolution] ScopeResolution +# 205| 0: [Constant] X +# 205| 1: [ReservedWord] :: +# 205| 2: [Identifier] foo +# 205| 2: [Do] Do +# 205| 0: [ReservedWord] do +# 206| 1: [ScopeResolution] ScopeResolution +# 206| 0: [Constant] X +# 206| 1: [ReservedWord] :: +# 206| 2: [Identifier] bar +# 207| 2: [ReservedWord] end +# 210| 59: [WhileModifier] WhileModifier +# 210| 0: [Identifier] bar +# 210| 1: [ReservedWord] while +# 210| 2: [Identifier] foo +# 211| 60: [WhileModifier] WhileModifier +# 211| 0: [ScopeResolution] ScopeResolution +# 211| 0: [Constant] X +# 211| 1: [ReservedWord] :: +# 211| 2: [Identifier] bar +# 211| 1: [ReservedWord] while +# 211| 2: [ScopeResolution] ScopeResolution +# 211| 0: [Constant] X +# 211| 1: [ReservedWord] :: +# 211| 2: [Identifier] foo +# 214| 61: [Until] Until +# 214| 0: [ReservedWord] until +# 214| 1: [Identifier] foo +# 214| 2: [Do] Do +# 214| 0: [ReservedWord] do +# 215| 1: [Identifier] bar +# 216| 2: [ReservedWord] end +# 217| 62: [Until] Until +# 217| 0: [ReservedWord] until +# 217| 1: [ScopeResolution] ScopeResolution +# 217| 0: [Constant] X +# 217| 1: [ReservedWord] :: +# 217| 2: [Identifier] foo +# 217| 2: [Do] Do +# 217| 0: [ReservedWord] do +# 218| 1: [ScopeResolution] ScopeResolution +# 218| 0: [Constant] X +# 218| 1: [ReservedWord] :: +# 218| 2: [Identifier] bar +# 219| 2: [ReservedWord] end +# 222| 63: [UntilModifier] UntilModifier +# 222| 0: [Identifier] bar +# 222| 1: [ReservedWord] until +# 222| 2: [Identifier] foo +# 223| 64: [UntilModifier] UntilModifier +# 223| 0: [ScopeResolution] ScopeResolution +# 223| 0: [Constant] X +# 223| 1: [ReservedWord] :: +# 223| 2: [Identifier] bar +# 223| 1: [ReservedWord] until +# 223| 2: [ScopeResolution] ScopeResolution +# 223| 0: [Constant] X +# 223| 1: [ReservedWord] :: +# 223| 2: [Identifier] foo +# 226| 65: [For] For +# 226| 0: [ReservedWord] for +# 226| 1: [Identifier] x +# 226| 2: [In] In +# 226| 0: [ReservedWord] in +# 226| 1: [Identifier] bar +# 226| 3: [Do] Do +# 227| 0: [Identifier] baz +# 228| 1: [ReservedWord] end +# 229| 66: [For] For +# 229| 0: [ReservedWord] for +# 229| 1: [Identifier] x +# 229| 2: [In] In +# 229| 0: [ReservedWord] in +# 229| 1: [ScopeResolution] ScopeResolution +# 229| 0: [Constant] X +# 229| 1: [ReservedWord] :: +# 229| 2: [Identifier] bar +# 229| 3: [Do] Do +# 230| 0: [ScopeResolution] ScopeResolution +# 230| 0: [Constant] X +# 230| 1: [ReservedWord] :: +# 230| 2: [Identifier] baz +# 231| 1: [ReservedWord] end +# 234| 67: [ElementReference] ElementReference +# 234| 0: [Identifier] foo +# 234| 1: [ReservedWord] [ +# 234| 2: [Identifier] bar +# 234| 3: [ReservedWord] ] +# 235| 68: [ElementReference] ElementReference +# 235| 0: [ScopeResolution] ScopeResolution +# 235| 0: [Constant] X +# 235| 1: [ReservedWord] :: +# 235| 2: [Identifier] foo +# 235| 1: [ReservedWord] [ +# 235| 2: [ScopeResolution] ScopeResolution +# 235| 0: [Constant] X +# 235| 1: [ReservedWord] :: +# 235| 2: [Identifier] bar +# 235| 3: [ReservedWord] ] +# 238| 69: [String] String +# 238| 0: [ReservedWord] " +# 238| 1: [StringContent] foo- +# 238| 2: [Interpolation] Interpolation +# 238| 0: [ReservedWord] #{ +# 238| 1: [Identifier] bar +# 238| 2: [ReservedWord] } +# 238| 3: [StringContent] - +# 238| 4: [Interpolation] Interpolation +# 238| 0: [ReservedWord] #{ +# 238| 1: [ScopeResolution] ScopeResolution +# 238| 0: [Constant] X +# 238| 1: [ReservedWord] :: +# 238| 2: [Identifier] baz +# 238| 2: [ReservedWord] } +# 238| 5: [ReservedWord] " +# 241| 70: [ScopeResolution] ScopeResolution +# 241| 0: [Identifier] foo +# 241| 1: [ReservedWord] :: +# 241| 2: [Constant] Bar +# 242| 71: [ScopeResolution] ScopeResolution +# 242| 0: [ScopeResolution] ScopeResolution +# 242| 0: [Constant] X +# 242| 1: [ReservedWord] :: +# 242| 2: [Identifier] foo +# 242| 1: [ReservedWord] :: +# 242| 2: [Constant] Bar +# 245| 72: [Range] Range +# 245| 0: [Identifier] foo +# 245| 1: [ReservedWord] .. +# 245| 2: [Identifier] bar +# 246| 73: [Range] Range +# 246| 0: [ScopeResolution] ScopeResolution +# 246| 0: [Constant] X +# 246| 1: [ReservedWord] :: +# 246| 2: [Identifier] foo +# 246| 1: [ReservedWord] .. +# 246| 2: [ScopeResolution] ScopeResolution +# 246| 0: [Constant] X +# 246| 1: [ReservedWord] :: +# 246| 2: [Identifier] bar +# 249| 74: [Hash] Hash +# 249| 0: [ReservedWord] { +# 249| 1: [Pair] Pair +# 249| 0: [Identifier] foo +# 249| 1: [ReservedWord] => +# 249| 2: [Identifier] bar +# 249| 2: [ReservedWord] , +# 249| 3: [Pair] Pair +# 249| 0: [ScopeResolution] ScopeResolution +# 249| 0: [Constant] X +# 249| 1: [ReservedWord] :: +# 249| 2: [Identifier] foo +# 249| 1: [ReservedWord] => +# 249| 2: [ScopeResolution] ScopeResolution +# 249| 0: [Constant] X +# 249| 1: [ReservedWord] :: +# 249| 2: [Identifier] bar +# 249| 4: [ReservedWord] } +# 252| 75: [Begin] Begin +# 252| 0: [ReservedWord] begin +# 253| 1: [Rescue] Rescue +# 253| 0: [ReservedWord] rescue +# 253| 1: [Exceptions] Exceptions +# 253| 0: [Identifier] foo +# 254| 2: [Ensure] Ensure +# 254| 0: [ReservedWord] ensure +# 254| 1: [Identifier] bar +# 255| 3: [ReservedWord] end +# 256| 76: [Begin] Begin +# 256| 0: [ReservedWord] begin +# 257| 1: [Rescue] Rescue +# 257| 0: [ReservedWord] rescue +# 257| 1: [Exceptions] Exceptions +# 257| 0: [ScopeResolution] ScopeResolution +# 257| 0: [Constant] X +# 257| 1: [ReservedWord] :: +# 257| 2: [Identifier] foo +# 258| 2: [Ensure] Ensure +# 258| 0: [ReservedWord] ensure +# 258| 1: [ScopeResolution] ScopeResolution +# 258| 0: [Constant] X +# 258| 1: [ReservedWord] :: +# 258| 2: [Identifier] bar +# 259| 3: [ReservedWord] end +# 262| 77: [RescueModifier] RescueModifier +# 262| 0: [Identifier] foo +# 262| 1: [ReservedWord] rescue +# 262| 2: [Identifier] bar +# 263| 78: [RescueModifier] RescueModifier +# 263| 0: [ScopeResolution] ScopeResolution +# 263| 0: [Constant] X +# 263| 1: [ReservedWord] :: +# 263| 2: [Identifier] foo +# 263| 1: [ReservedWord] rescue +# 263| 2: [ScopeResolution] ScopeResolution +# 263| 0: [Constant] X +# 263| 1: [ReservedWord] :: +# 263| 2: [Identifier] bar +# 266| 79: [Call] Call +# 266| 0: [Identifier] foo +# 266| 1: [ArgumentList] ArgumentList +# 266| 0: [ReservedWord] ( +# 266| 1: [BlockArgument] BlockArgument +# 266| 0: [ReservedWord] & +# 266| 1: [Identifier] bar +# 266| 2: [ReservedWord] ) +# 267| 80: [Call] Call +# 267| 0: [Identifier] foo +# 267| 1: [ArgumentList] ArgumentList +# 267| 0: [ReservedWord] ( +# 267| 1: [BlockArgument] BlockArgument +# 267| 0: [ReservedWord] & +# 267| 1: [ScopeResolution] ScopeResolution +# 267| 0: [Constant] X +# 267| 1: [ReservedWord] :: +# 267| 2: [Identifier] bar +# 267| 2: [ReservedWord] ) +# 268| 81: [Call] Call +# 268| 0: [Identifier] foo +# 268| 1: [ArgumentList] ArgumentList +# 268| 0: [ReservedWord] ( +# 268| 1: [BlockArgument] BlockArgument +# 268| 0: [ReservedWord] & +# 268| 2: [ReservedWord] ) +# 270| 82: [Call] Call +# 270| 0: [Identifier] foo +# 270| 1: [ArgumentList] ArgumentList +# 270| 0: [ReservedWord] ( +# 270| 1: [SplatArgument] SplatArgument +# 270| 0: [ReservedWord] * +# 270| 1: [Identifier] bar +# 270| 2: [ReservedWord] ) +# 271| 83: [Call] Call +# 271| 0: [Identifier] foo +# 271| 1: [ArgumentList] ArgumentList +# 271| 0: [ReservedWord] ( +# 271| 1: [SplatArgument] SplatArgument +# 271| 0: [ReservedWord] * +# 271| 1: [ScopeResolution] ScopeResolution +# 271| 0: [Constant] X +# 271| 1: [ReservedWord] :: +# 271| 2: [Identifier] bar +# 271| 2: [ReservedWord] ) +# 274| 84: [Call] Call +# 274| 0: [Identifier] foo +# 274| 1: [ArgumentList] ArgumentList +# 274| 0: [ReservedWord] ( +# 274| 1: [HashSplatArgument] HashSplatArgument +# 274| 0: [ReservedWord] ** +# 274| 1: [Identifier] bar +# 274| 2: [ReservedWord] ) +# 275| 85: [Call] Call +# 275| 0: [Identifier] foo +# 275| 1: [ArgumentList] ArgumentList +# 275| 0: [ReservedWord] ( +# 275| 1: [HashSplatArgument] HashSplatArgument +# 275| 0: [ReservedWord] ** +# 275| 1: [ScopeResolution] ScopeResolution +# 275| 0: [Constant] X +# 275| 1: [ReservedWord] :: +# 275| 2: [Identifier] bar +# 275| 2: [ReservedWord] ) +# 278| 86: [Call] Call +# 278| 0: [Identifier] foo +# 278| 1: [ArgumentList] ArgumentList +# 278| 0: [ReservedWord] ( +# 278| 1: [Pair] Pair +# 278| 0: [HashKeySymbol] blah +# 278| 1: [ReservedWord] : +# 278| 2: [Identifier] bar +# 278| 2: [ReservedWord] ) +# 279| 87: [Call] Call +# 279| 0: [Identifier] foo +# 279| 1: [ArgumentList] ArgumentList +# 279| 0: [ReservedWord] ( +# 279| 1: [Pair] Pair +# 279| 0: [HashKeySymbol] blah +# 279| 1: [ReservedWord] : +# 279| 2: [ScopeResolution] ScopeResolution +# 279| 0: [Constant] X +# 279| 1: [ReservedWord] :: +# 279| 2: [Identifier] bar +# 279| 2: [ReservedWord] ) +# 284| 88: [Class] Class +# 284| 0: [ReservedWord] class +# 284| 1: [Constant] MyClass +# 285| 2: [Method] Method +# 285| 0: [ReservedWord] def +# 285| 1: [Identifier] my_method +# 286| 2: [Super] super +# 287| 3: [Call] Call +# 287| 0: [Super] super +# 287| 1: [ArgumentList] ArgumentList +# 287| 0: [ReservedWord] ( +# 287| 1: [ReservedWord] ) +# 288| 4: [Call] Call +# 288| 0: [Super] super +# 288| 1: [ArgumentList] ArgumentList +# 288| 0: [String] String +# 288| 0: [ReservedWord] ' +# 288| 1: [StringContent] blah +# 288| 2: [ReservedWord] ' +# 289| 5: [Call] Call +# 289| 0: [Super] super +# 289| 1: [ArgumentList] ArgumentList +# 289| 0: [Integer] 1 +# 289| 1: [ReservedWord] , +# 289| 2: [Integer] 2 +# 289| 3: [ReservedWord] , +# 289| 4: [Integer] 3 +# 290| 6: [Call] Call +# 290| 0: [Super] super +# 290| 1: [Block] Block +# 290| 0: [ReservedWord] { +# 290| 1: [BlockParameters] BlockParameters +# 290| 0: [ReservedWord] | +# 290| 1: [Identifier] x +# 290| 2: [ReservedWord] | +# 290| 2: [Binary] Binary +# 290| 0: [Identifier] x +# 290| 1: [ReservedWord] + +# 290| 2: [Integer] 1 +# 290| 3: [ReservedWord] } +# 291| 7: [Call] Call +# 291| 0: [Super] super +# 291| 1: [DoBlock] DoBlock +# 291| 0: [ReservedWord] do +# 291| 1: [BlockParameters] BlockParameters +# 291| 0: [ReservedWord] | +# 291| 1: [Identifier] x +# 291| 2: [ReservedWord] | +# 291| 2: [Binary] Binary +# 291| 0: [Identifier] x +# 291| 1: [ReservedWord] * +# 291| 2: [Integer] 2 +# 291| 3: [ReservedWord] end +# 292| 8: [Call] Call +# 292| 0: [Super] super +# 292| 1: [ArgumentList] ArgumentList +# 292| 0: [Integer] 4 +# 292| 1: [ReservedWord] , +# 292| 2: [Integer] 5 +# 292| 2: [Block] Block +# 292| 0: [ReservedWord] { +# 292| 1: [BlockParameters] BlockParameters +# 292| 0: [ReservedWord] | +# 292| 1: [Identifier] x +# 292| 2: [ReservedWord] | +# 292| 2: [Binary] Binary +# 292| 0: [Identifier] x +# 292| 1: [ReservedWord] + +# 292| 2: [Integer] 100 +# 292| 3: [ReservedWord] } +# 293| 9: [Call] Call +# 293| 0: [Super] super +# 293| 1: [ArgumentList] ArgumentList +# 293| 0: [Integer] 6 +# 293| 1: [ReservedWord] , +# 293| 2: [Integer] 7 +# 293| 2: [DoBlock] DoBlock +# 293| 0: [ReservedWord] do +# 293| 1: [BlockParameters] BlockParameters +# 293| 0: [ReservedWord] | +# 293| 1: [Identifier] x +# 293| 2: [ReservedWord] | +# 293| 2: [Binary] Binary +# 293| 0: [Identifier] x +# 293| 1: [ReservedWord] + +# 293| 2: [Integer] 200 +# 293| 3: [ReservedWord] end +# 294| 10: [ReservedWord] end +# 295| 3: [ReservedWord] end +# 301| 89: [Class] Class +# 301| 0: [ReservedWord] class +# 301| 1: [Constant] AnotherClass +# 302| 2: [Method] Method +# 302| 0: [ReservedWord] def +# 302| 1: [Identifier] another_method +# 303| 2: [Call] Call +# 303| 0: [Identifier] foo +# 303| 1: [ReservedWord] . +# 303| 2: [Identifier] super +# 304| 3: [Call] Call +# 304| 0: [Self] self +# 304| 1: [ReservedWord] . +# 304| 2: [Identifier] super +# 305| 4: [Call] Call +# 305| 0: [Super] super +# 305| 1: [ReservedWord] . +# 305| 2: [Identifier] super +# 306| 5: [ReservedWord] end +# 307| 3: [ReservedWord] end +# 310| 90: [Call] Call +# 310| 0: [Identifier] foo +# 310| 1: [ReservedWord] . +# 310| 2: [ArgumentList] ArgumentList +# 310| 0: [ReservedWord] ( +# 310| 1: [ReservedWord] ) +# 311| 91: [Call] Call +# 311| 0: [Identifier] foo +# 311| 1: [ReservedWord] . +# 311| 2: [ArgumentList] ArgumentList +# 311| 0: [ReservedWord] ( +# 311| 1: [Integer] 1 +# 311| 2: [ReservedWord] ) +# 314| 92: [Assignment] Assignment +# 314| 0: [Call] Call +# 314| 0: [Self] self +# 314| 1: [ReservedWord] . +# 314| 2: [Identifier] foo +# 314| 1: [ReservedWord] = +# 314| 2: [Integer] 10 +# 315| 93: [Assignment] Assignment +# 315| 0: [ElementReference] ElementReference +# 315| 0: [Identifier] foo +# 315| 1: [ReservedWord] [ +# 315| 2: [Integer] 0 +# 315| 3: [ReservedWord] ] +# 315| 1: [ReservedWord] = +# 315| 2: [Integer] 10 +# 316| 94: [Assignment] Assignment +# 316| 0: [LeftAssignmentList] LeftAssignmentList +# 316| 0: [Call] Call +# 316| 0: [Self] self +# 316| 1: [ReservedWord] . +# 316| 2: [Identifier] foo +# 316| 1: [ReservedWord] , +# 316| 2: [RestAssignment] RestAssignment +# 316| 0: [ReservedWord] * +# 316| 1: [Call] Call +# 316| 0: [Self] self +# 316| 1: [ReservedWord] . +# 316| 2: [Identifier] bar +# 316| 3: [ReservedWord] , +# 316| 4: [ElementReference] ElementReference +# 316| 0: [Identifier] foo +# 316| 1: [ReservedWord] [ +# 316| 2: [Integer] 4 +# 316| 3: [ReservedWord] ] +# 316| 1: [ReservedWord] = +# 316| 2: [Array] Array +# 316| 0: [ReservedWord] [ +# 316| 1: [Integer] 1 +# 316| 2: [ReservedWord] , +# 316| 3: [Integer] 2 +# 316| 4: [ReservedWord] , +# 316| 5: [Integer] 3 +# 316| 6: [ReservedWord] , +# 316| 7: [Integer] 4 +# 316| 8: [ReservedWord] ] +# 317| 95: [Assignment] Assignment +# 317| 0: [LeftAssignmentList] LeftAssignmentList +# 317| 0: [Identifier] a +# 317| 1: [ReservedWord] , +# 317| 2: [RestAssignment] RestAssignment +# 317| 0: [ReservedWord] * +# 317| 1: [ElementReference] ElementReference +# 317| 0: [Identifier] foo +# 317| 1: [ReservedWord] [ +# 317| 2: [Integer] 5 +# 317| 3: [ReservedWord] ] +# 317| 1: [ReservedWord] = +# 317| 2: [Array] Array +# 317| 0: [ReservedWord] [ +# 317| 1: [Integer] 1 +# 317| 2: [ReservedWord] , +# 317| 3: [Integer] 2 +# 317| 4: [ReservedWord] , +# 317| 5: [Integer] 3 +# 317| 6: [ReservedWord] ] +# 318| 96: [OperatorAssignment] OperatorAssignment +# 318| 0: [Call] Call +# 318| 0: [Self] self +# 318| 1: [ReservedWord] . +# 318| 2: [Identifier] count +# 318| 1: [ReservedWord] += +# 318| 2: [Integer] 1 +# 319| 97: [OperatorAssignment] OperatorAssignment +# 319| 0: [ElementReference] ElementReference +# 319| 0: [Identifier] foo +# 319| 1: [ReservedWord] [ +# 319| 2: [Integer] 0 +# 319| 3: [ReservedWord] ] +# 319| 1: [ReservedWord] += +# 319| 2: [Integer] 1 +# 320| 98: [OperatorAssignment] OperatorAssignment +# 320| 0: [ElementReference] ElementReference +# 320| 0: [Call] Call +# 320| 0: [Identifier] foo +# 320| 1: [ReservedWord] . +# 320| 2: [Identifier] bar +# 320| 1: [ReservedWord] [ +# 320| 2: [Integer] 0 +# 320| 3: [ReservedWord] , +# 320| 4: [Call] Call +# 320| 0: [Identifier] foo +# 320| 1: [ReservedWord] . +# 320| 2: [Identifier] baz +# 320| 5: [ReservedWord] , +# 320| 6: [Binary] Binary +# 320| 0: [Call] Call +# 320| 0: [Identifier] foo +# 320| 1: [ReservedWord] . +# 320| 2: [Identifier] boo +# 320| 1: [ReservedWord] + +# 320| 2: [Integer] 1 +# 320| 7: [ReservedWord] ] +# 320| 1: [ReservedWord] *= +# 320| 2: [Integer] 2 +# 323| 99: [Method] Method +# 323| 0: [ReservedWord] def +# 323| 1: [Identifier] foo +# 323| 2: [ReservedWord] = +# 323| 3: [Identifier] bar +# 324| 100: [Method] Method +# 324| 0: [ReservedWord] def +# 324| 1: [Identifier] foo +# 324| 2: [MethodParameters] MethodParameters +# 324| 0: [ReservedWord] ( +# 324| 1: [ReservedWord] ) +# 324| 3: [ReservedWord] = +# 324| 4: [Identifier] bar +# 325| 101: [Method] Method +# 325| 0: [ReservedWord] def +# 325| 1: [Identifier] foo +# 325| 2: [MethodParameters] MethodParameters +# 325| 0: [ReservedWord] ( +# 325| 1: [Identifier] x +# 325| 2: [ReservedWord] ) +# 325| 3: [ReservedWord] = +# 325| 4: [Identifier] bar +# 326| 102: [SingletonMethod] SingletonMethod +# 326| 0: [ReservedWord] def +# 326| 1: [Constant] Object +# 326| 2: [ReservedWord] . +# 326| 3: [Identifier] foo +# 326| 4: [ReservedWord] = +# 326| 5: [Identifier] bar +# 327| 103: [SingletonMethod] SingletonMethod +# 327| 0: [ReservedWord] def +# 327| 1: [Constant] Object +# 327| 2: [ReservedWord] . +# 327| 3: [Identifier] foo +# 327| 4: [MethodParameters] MethodParameters +# 327| 0: [ReservedWord] ( +# 327| 1: [Identifier] x +# 327| 2: [ReservedWord] ) +# 327| 5: [ReservedWord] = +# 327| 6: [Identifier] bar +# 328| 104: [Method] Method +# 328| 0: [ReservedWord] def +# 328| 1: [Identifier] foo +# 328| 2: [MethodParameters] MethodParameters +# 328| 0: [ReservedWord] ( +# 328| 1: [ReservedWord] ) +# 328| 3: [ReservedWord] = +# 328| 4: [RescueModifier] RescueModifier +# 328| 0: [Identifier] bar +# 328| 1: [ReservedWord] rescue +# 328| 2: [ParenthesizedStatements] ParenthesizedStatements +# 328| 0: [ReservedWord] ( +# 328| 1: [Call] Call +# 328| 0: [Identifier] print +# 328| 1: [ArgumentList] ArgumentList +# 328| 0: [String] String +# 328| 0: [ReservedWord] " +# 328| 1: [StringContent] error +# 328| 2: [ReservedWord] " +# 328| 2: [ReservedWord] ) +# 331| 105: [Method] Method +# 331| 0: [ReservedWord] def +# 331| 1: [Identifier] foo +# 331| 2: [MethodParameters] MethodParameters +# 331| 0: [ReservedWord] ( +# 331| 1: [ForwardParameter] ... +# 331| 0: [ReservedWord] ... +# 331| 2: [ReservedWord] ) +# 332| 3: [Call] Call +# 332| 0: [Super] super +# 332| 1: [ArgumentList] ArgumentList +# 332| 0: [ReservedWord] ( +# 332| 1: [ForwardArgument] ... +# 332| 0: [ReservedWord] ... +# 332| 2: [ReservedWord] ) +# 333| 4: [ReservedWord] end +# 335| 106: [Method] Method +# 335| 0: [ReservedWord] def +# 335| 1: [Identifier] foo +# 335| 2: [MethodParameters] MethodParameters +# 335| 0: [ReservedWord] ( +# 335| 1: [Identifier] a +# 335| 2: [ReservedWord] , +# 335| 3: [Identifier] b +# 335| 4: [ReservedWord] , +# 335| 5: [ForwardParameter] ... +# 335| 0: [ReservedWord] ... +# 335| 6: [ReservedWord] ) +# 336| 3: [Call] Call +# 336| 0: [Identifier] bar +# 336| 1: [ArgumentList] ArgumentList +# 336| 0: [ReservedWord] ( +# 336| 1: [Identifier] b +# 336| 2: [ReservedWord] , +# 336| 3: [ForwardArgument] ... +# 336| 0: [ReservedWord] ... +# 336| 4: [ReservedWord] ) +# 337| 4: [ReservedWord] end +# 340| 107: [For] For +# 340| 0: [ReservedWord] for +# 340| 1: [LeftAssignmentList] LeftAssignmentList +# 340| 0: [Identifier] x +# 340| 1: [ReservedWord] , +# 340| 2: [Identifier] y +# 340| 3: [ReservedWord] , +# 340| 4: [Identifier] z +# 340| 2: [In] In +# 340| 0: [ReservedWord] in +# 340| 1: [Array] Array +# 340| 0: [ReservedWord] [ +# 340| 1: [Array] Array +# 340| 0: [ReservedWord] [ +# 340| 1: [Integer] 1 +# 340| 2: [ReservedWord] , +# 340| 3: [Integer] 2 +# 340| 4: [ReservedWord] , +# 340| 5: [Integer] 3 +# 340| 6: [ReservedWord] ] +# 340| 2: [ReservedWord] , +# 340| 3: [Array] Array +# 340| 0: [ReservedWord] [ +# 340| 1: [Integer] 4 +# 340| 2: [ReservedWord] , +# 340| 3: [Integer] 5 +# 340| 4: [ReservedWord] , +# 340| 5: [Integer] 6 +# 340| 6: [ReservedWord] ] +# 340| 4: [ReservedWord] ] +# 340| 3: [Do] Do +# 341| 0: [Call] Call +# 341| 0: [Identifier] foo +# 341| 1: [ArgumentList] ArgumentList +# 341| 0: [Identifier] x +# 341| 1: [ReservedWord] , +# 341| 2: [Identifier] y +# 341| 3: [ReservedWord] , +# 341| 4: [Identifier] z +# 342| 1: [ReservedWord] end +# 344| 108: [Call] Call +# 344| 0: [Identifier] foo +# 344| 1: [ArgumentList] ArgumentList +# 344| 0: [ReservedWord] ( +# 344| 1: [Pair] Pair +# 344| 0: [HashKeySymbol] x +# 344| 1: [ReservedWord] : +# 344| 2: [Integer] 42 +# 344| 2: [ReservedWord] ) +# 345| 109: [Call] Call +# 345| 0: [Identifier] foo +# 345| 1: [ArgumentList] ArgumentList +# 345| 0: [ReservedWord] ( +# 345| 1: [Pair] Pair +# 345| 0: [HashKeySymbol] x +# 345| 1: [ReservedWord] : +# 345| 2: [ReservedWord] , +# 345| 3: [Pair] Pair +# 345| 0: [HashKeySymbol] novar +# 345| 1: [ReservedWord] : +# 345| 4: [ReservedWord] ) +# 346| 110: [Call] Call +# 346| 0: [Identifier] foo +# 346| 1: [ArgumentList] ArgumentList +# 346| 0: [ReservedWord] ( +# 346| 1: [Pair] Pair +# 346| 0: [HashKeySymbol] X +# 346| 1: [ReservedWord] : +# 346| 2: [Integer] 42 +# 346| 2: [ReservedWord] ) +# 347| 111: [Call] Call +# 347| 0: [Identifier] foo +# 347| 1: [ArgumentList] ArgumentList +# 347| 0: [ReservedWord] ( +# 347| 1: [Pair] Pair +# 347| 0: [HashKeySymbol] X +# 347| 1: [ReservedWord] : +# 347| 2: [ReservedWord] ) +# 350| 112: [Assignment] Assignment +# 350| 0: [Identifier] y +# 350| 1: [ReservedWord] = +# 350| 2: [Integer] 1 +# 351| 113: [Assignment] Assignment +# 351| 0: [Identifier] one +# 351| 1: [ReservedWord] = +# 351| 2: [Lambda] Lambda +# 351| 0: [ReservedWord] -> +# 351| 1: [LambdaParameters] LambdaParameters +# 351| 0: [ReservedWord] ( +# 351| 1: [Identifier] x +# 351| 2: [ReservedWord] ) +# 351| 2: [Block] Block +# 351| 0: [ReservedWord] { +# 351| 1: [Identifier] y +# 351| 2: [ReservedWord] } +# 352| 114: [Assignment] Assignment +# 352| 0: [Identifier] f +# 352| 1: [ReservedWord] = +# 352| 2: [Lambda] Lambda +# 352| 0: [ReservedWord] -> +# 352| 1: [LambdaParameters] LambdaParameters +# 352| 0: [ReservedWord] ( +# 352| 1: [Identifier] x +# 352| 2: [ReservedWord] ) +# 352| 2: [Block] Block +# 352| 0: [ReservedWord] { +# 352| 1: [Call] Call +# 352| 0: [Identifier] foo +# 352| 1: [ArgumentList] ArgumentList +# 352| 0: [Identifier] x +# 352| 2: [ReservedWord] } +# 353| 115: [Assignment] Assignment +# 353| 0: [Identifier] g +# 353| 1: [ReservedWord] = +# 353| 2: [Lambda] Lambda +# 353| 0: [ReservedWord] -> +# 353| 1: [LambdaParameters] LambdaParameters +# 353| 0: [ReservedWord] ( +# 353| 1: [Identifier] x +# 353| 2: [ReservedWord] ) +# 353| 2: [Block] Block +# 353| 0: [ReservedWord] { +# 353| 1: [Identifier] unknown_call +# 353| 2: [ReservedWord] } +# 354| 116: [Assignment] Assignment +# 354| 0: [Identifier] h +# 354| 1: [ReservedWord] = +# 354| 2: [Lambda] Lambda +# 354| 0: [ReservedWord] -> +# 354| 1: [LambdaParameters] LambdaParameters +# 354| 0: [ReservedWord] ( +# 354| 1: [Identifier] x +# 354| 2: [ReservedWord] ) +# 354| 2: [DoBlock] DoBlock +# 354| 0: [ReservedWord] do +# 355| 1: [Identifier] x +# 356| 2: [Identifier] y +# 357| 3: [Identifier] unknown_call +# 358| 4: [ReservedWord] end +# 1| [Comment] # call with no receiver, arguments, or block +# 4| [Comment] # call whose name is a scope resolution +# 7| [Comment] # call whose name is a global scope resolution +# 10| [Comment] # call with a receiver, no arguments or block +# 13| [Comment] # call with arguments +# 16| [Comment] # call with curly brace block +# 19| [Comment] # call with do block +# 24| [Comment] # call with receiver, arguments, and a block +# 29| [Comment] # a yield call +# 34| [Comment] # a yield call with arguments +# 39| [Comment] # ------------------------------------------------------------------------------ +# 40| [Comment] # Calls without parentheses or arguments are parsed by tree-sitter simply as +# 41| [Comment] # `identifier` nodes (or `scope_resolution` nodes whose `name` field is an +# 42| [Comment] # `identifier), so here we test that our AST library correctly represents them +# 43| [Comment] # as calls in all the following contexts. +# 45| [Comment] # root level (child of program) +# 49| [Comment] # in a parenthesized statement +# 53| [Comment] # in an argument list +# 57| [Comment] # in an array +# 61| [Comment] # RHS of an assignment +# 65| [Comment] # RHS an operator assignment +# 69| [Comment] # RHS assignment list +# 72| [Comment] # in a begin-end block +# 78| [Comment] # in a BEGIN block +# 81| [Comment] # in an END block +# 84| [Comment] # both operands of a binary operation +# 87| [Comment] # unary operand +# 91| [Comment] # in a curly brace block +# 94| [Comment] # in a do-end block +# 100| [Comment] # the receiver in a call can itself be a call +# 104| [Comment] # the value for a case expr +# 105| [Comment] # and the when pattern and body +# 115| [Comment] # in a class definition +# 121| [Comment] # in a superclass +# 127| [Comment] # in a singleton class value or body +# 135| [Comment] # in a method body +# 141| [Comment] # in a singleton method object or body +# 147| [Comment] # in the default value for a keyword parameter +# 153| [Comment] # in the default value for an optional parameter +# 159| [Comment] # in a module +# 165| [Comment] # ternary if: condition, consequence, and alternative can all be calls +# 169| [Comment] # if/elsif/else conditions and bodies +# 185| [Comment] # if-modifier condition/body +# 189| [Comment] # unless condition/body +# 197| [Comment] # unless-modifier condition/body +# 201| [Comment] # while loop condition/body +# 209| [Comment] # while-modifier loop condition/body +# 213| [Comment] # until loop condition/body +# 221| [Comment] # until-modifier loop condition/body +# 225| [Comment] # the collection being iterated over in a for loop, and the body +# 233| [Comment] # in an array indexing operation, both the object and the index can be calls +# 237| [Comment] # interpolation +# 240| [Comment] # the scope in a scope resolution +# 244| [Comment] # in a range +# 248| [Comment] # the key/value in a hash pair +# 251| [Comment] # rescue exceptions and ensure +# 261| [Comment] # rescue-modifier body and handler +# 265| [Comment] # block argument +# 269| [Comment] # splat argument +# 273| [Comment] # hash-splat argument +# 277| [Comment] # the value in a keyword argument +# 281| [Comment] # ------------------------------------------------------------------------------ +# 282| [Comment] # calls to `super` +# 297| [Comment] # ------------------------------------------------------------------------------ +# 298| [Comment] # calls to methods simply named `super`, i.e. *not* calls to the same method in +# 299| [Comment] # a parent classs, so these should be Call but not SuperCall +# 305| [Comment] # we expect the receiver to be a SuperCall, while the outer call should not (it's just a regular Call) +# 309| [Comment] # calls without method name +# 313| [Comment] # setter calls +# 322| [Comment] # endless method definitions +# 330| [Comment] # forward parameter and forwarded arguments +# 339| [Comment] # for loop over nested array +# 349| [Comment] # calls inside lambdas +constants/constants.rb: +# 1| [Program] Program +# 1| 0: [Module] Module +# 1| 0: [ReservedWord] module +# 1| 1: [Constant] ModuleA +# 2| 2: [Class] Class +# 2| 0: [ReservedWord] class +# 2| 1: [Constant] ClassA +# 3| 2: [Assignment] Assignment +# 3| 0: [Constant] CONST_A +# 3| 1: [ReservedWord] = +# 3| 2: [String] String +# 3| 0: [ReservedWord] " +# 3| 1: [StringContent] const_a +# 3| 2: [ReservedWord] " +# 4| 3: [ReservedWord] end +# 6| 3: [Assignment] Assignment +# 6| 0: [Constant] CONST_B +# 6| 1: [ReservedWord] = +# 6| 2: [String] String +# 6| 0: [ReservedWord] " +# 6| 1: [StringContent] const_b +# 6| 2: [ReservedWord] " +# 8| 4: [Module] Module +# 8| 0: [ReservedWord] module +# 8| 1: [Constant] ModuleB +# 9| 2: [Class] Class +# 9| 0: [ReservedWord] class +# 9| 1: [Constant] ClassB +# 9| 2: [Superclass] Superclass +# 9| 0: [ReservedWord] < +# 9| 1: [Constant] Base +# 10| 3: [ReservedWord] end +# 12| 3: [Class] Class +# 12| 0: [ReservedWord] class +# 12| 1: [Constant] ClassC +# 12| 2: [Superclass] Superclass +# 12| 0: [ReservedWord] < +# 12| 1: [ScopeResolution] ScopeResolution +# 12| 0: [ScopeResolution] ScopeResolution +# 12| 0: [Constant] X +# 12| 1: [ReservedWord] :: +# 12| 2: [Constant] Y +# 12| 1: [ReservedWord] :: +# 12| 2: [Constant] Z +# 13| 3: [ReservedWord] end +# 14| 4: [ReservedWord] end +# 15| 5: [ReservedWord] end +# 17| 1: [Assignment] Assignment +# 17| 0: [Constant] GREETING +# 17| 1: [ReservedWord] = +# 17| 2: [Binary] Binary +# 17| 0: [Binary] Binary +# 17| 0: [String] String +# 17| 0: [ReservedWord] ' +# 17| 1: [StringContent] Hello +# 17| 2: [ReservedWord] ' +# 17| 1: [ReservedWord] + +# 17| 2: [ScopeResolution] ScopeResolution +# 17| 0: [ScopeResolution] ScopeResolution +# 17| 0: [Constant] ModuleA +# 17| 1: [ReservedWord] :: +# 17| 2: [Constant] ClassA +# 17| 1: [ReservedWord] :: +# 17| 2: [Constant] CONST_A +# 17| 1: [ReservedWord] + +# 17| 2: [ScopeResolution] ScopeResolution +# 17| 0: [Constant] ModuleA +# 17| 1: [ReservedWord] :: +# 17| 2: [Constant] CONST_B +# 19| 2: [Method] Method +# 19| 0: [ReservedWord] def +# 19| 1: [Identifier] foo +# 20| 2: [Assignment] Assignment +# 20| 0: [Constant] Names +# 20| 1: [ReservedWord] = +# 20| 2: [Array] Array +# 20| 0: [ReservedWord] [ +# 20| 1: [String] String +# 20| 0: [ReservedWord] ' +# 20| 1: [StringContent] Vera +# 20| 2: [ReservedWord] ' +# 20| 2: [ReservedWord] , +# 20| 3: [String] String +# 20| 0: [ReservedWord] ' +# 20| 1: [StringContent] Chuck +# 20| 2: [ReservedWord] ' +# 20| 4: [ReservedWord] , +# 20| 5: [String] String +# 20| 0: [ReservedWord] ' +# 20| 1: [StringContent] Dave +# 20| 2: [ReservedWord] ' +# 20| 6: [ReservedWord] ] +# 22| 3: [Call] Call +# 22| 0: [Constant] Names +# 22| 1: [ReservedWord] . +# 22| 2: [Identifier] each +# 22| 3: [DoBlock] DoBlock +# 22| 0: [ReservedWord] do +# 22| 1: [BlockParameters] BlockParameters +# 22| 0: [ReservedWord] | +# 22| 1: [Identifier] name +# 22| 2: [ReservedWord] | +# 23| 2: [Call] Call +# 23| 0: [Identifier] puts +# 23| 1: [ArgumentList] ArgumentList +# 23| 0: [String] String +# 23| 0: [ReservedWord] " +# 23| 1: [Interpolation] Interpolation +# 23| 0: [ReservedWord] #{ +# 23| 1: [Constant] GREETING +# 23| 2: [ReservedWord] } +# 23| 2: [StringContent] +# 23| 3: [Interpolation] Interpolation +# 23| 0: [ReservedWord] #{ +# 23| 1: [Identifier] name +# 23| 2: [ReservedWord] } +# 23| 4: [ReservedWord] " +# 24| 3: [ReservedWord] end +# 28| 4: [Call] Call +# 28| 0: [Constant] Array +# 28| 1: [ArgumentList] ArgumentList +# 28| 0: [ReservedWord] ( +# 28| 1: [String] String +# 28| 0: [ReservedWord] ' +# 28| 1: [StringContent] foo +# 28| 2: [ReservedWord] ' +# 28| 2: [ReservedWord] ) +# 29| 5: [ReservedWord] end +# 31| 3: [Class] Class +# 31| 0: [ReservedWord] class +# 31| 1: [ScopeResolution] ScopeResolution +# 31| 0: [Constant] ModuleA +# 31| 1: [ReservedWord] :: +# 31| 2: [Constant] ClassD +# 31| 2: [Superclass] Superclass +# 31| 0: [ReservedWord] < +# 31| 1: [ScopeResolution] ScopeResolution +# 31| 0: [Constant] ModuleA +# 31| 1: [ReservedWord] :: +# 31| 2: [Constant] ClassA +# 32| 3: [Assignment] Assignment +# 32| 0: [Constant] FOURTY_TWO +# 32| 1: [ReservedWord] = +# 32| 2: [Integer] 42 +# 33| 4: [ReservedWord] end +# 35| 4: [Module] Module +# 35| 0: [ReservedWord] module +# 35| 1: [ScopeResolution] ScopeResolution +# 35| 0: [Constant] ModuleA +# 35| 1: [ReservedWord] :: +# 35| 2: [Constant] ModuleC +# 36| 2: [Assignment] Assignment +# 36| 0: [Constant] FOURTY_THREE +# 36| 1: [ReservedWord] = +# 36| 2: [Integer] 43 +# 37| 3: [ReservedWord] end +# 39| 5: [Assignment] Assignment +# 39| 0: [ScopeResolution] ScopeResolution +# 39| 0: [ScopeResolution] ScopeResolution +# 39| 0: [Constant] ModuleA +# 39| 1: [ReservedWord] :: +# 39| 2: [Constant] ModuleB +# 39| 1: [ReservedWord] :: +# 39| 2: [Constant] MAX_SIZE +# 39| 1: [ReservedWord] = +# 39| 2: [Integer] 1024 +# 41| 6: [Call] Call +# 41| 0: [Identifier] puts +# 41| 1: [ArgumentList] ArgumentList +# 41| 0: [ScopeResolution] ScopeResolution +# 41| 0: [ScopeResolution] ScopeResolution +# 41| 0: [Constant] ModuleA +# 41| 1: [ReservedWord] :: +# 41| 2: [Constant] ModuleB +# 41| 1: [ReservedWord] :: +# 41| 2: [Constant] MAX_SIZE +# 43| 7: [Call] Call +# 43| 0: [Identifier] puts +# 43| 1: [ArgumentList] ArgumentList +# 43| 0: [Constant] GREETING +# 44| 8: [Call] Call +# 44| 0: [Identifier] puts +# 44| 1: [ArgumentList] ArgumentList +# 44| 0: [ScopeResolution] ScopeResolution +# 44| 0: [ReservedWord] :: +# 44| 1: [Constant] GREETING +# 46| 9: [Module] Module +# 46| 0: [ReservedWord] module +# 46| 1: [ScopeResolution] ScopeResolution +# 46| 0: [Constant] ModuleA +# 46| 1: [ReservedWord] :: +# 46| 2: [Constant] ModuleB +# 47| 2: [Class] Class +# 47| 0: [ReservedWord] class +# 47| 1: [Constant] ClassB +# 47| 2: [Superclass] Superclass +# 47| 0: [ReservedWord] < +# 47| 1: [Constant] Base +# 48| 3: [Assignment] Assignment +# 48| 0: [Constant] FOURTY_ONE +# 48| 1: [ReservedWord] = +# 48| 2: [Integer] 41 +# 49| 4: [ReservedWord] end +# 50| 3: [ReservedWord] end +# 52| 10: [Module] Module +# 52| 0: [ReservedWord] module +# 52| 1: [Constant] ModuleA +# 53| 2: [Assignment] Assignment +# 53| 0: [Constant] FOURTY_FOUR +# 53| 1: [ReservedWord] = +# 53| 2: [String] String +# 53| 0: [ReservedWord] " +# 53| 1: [StringContent] fourty-four +# 53| 2: [ReservedWord] " +# 54| 3: [Class] Class +# 54| 0: [ReservedWord] class +# 54| 1: [ScopeResolution] ScopeResolution +# 54| 0: [Constant] ModuleB +# 54| 1: [ReservedWord] :: +# 54| 2: [Constant] ClassB +# 54| 2: [Superclass] Superclass +# 54| 0: [ReservedWord] < +# 54| 1: [Constant] Base +# 55| 3: [Assignment] Assignment +# 55| 0: [ClassVariable] @@fourty_four +# 55| 1: [ReservedWord] = +# 55| 2: [Constant] FOURTY_FOUR +# 56| 4: [Assignment] Assignment +# 56| 0: [Constant] FOURTY_FOUR +# 56| 1: [ReservedWord] = +# 56| 2: [Integer] 44 +# 57| 5: [Assignment] Assignment +# 57| 0: [ClassVariable] @@fourty_four +# 57| 1: [ReservedWord] = +# 57| 2: [Constant] FOURTY_FOUR +# 58| 6: [ReservedWord] end +# 59| 4: [ReservedWord] end +# 61| 11: [Module] Module +# 61| 0: [ReservedWord] module +# 61| 1: [Constant] Mod1 +# 62| 2: [Module] Module +# 62| 0: [ReservedWord] module +# 62| 1: [Constant] Mod3 +# 63| 2: [Assignment] Assignment +# 63| 0: [Constant] FOURTY_FIVE +# 63| 1: [ReservedWord] = +# 63| 2: [Integer] 45 +# 64| 3: [ReservedWord] end +# 65| 3: [Assignment] Assignment +# 65| 0: [ClassVariable] @@fourty_five +# 65| 1: [ReservedWord] = +# 65| 2: [ScopeResolution] ScopeResolution +# 65| 0: [Constant] Mod3 +# 65| 1: [ReservedWord] :: +# 65| 2: [Constant] FOURTY_FIVE +# 66| 4: [ReservedWord] end +# 68| 12: [Module] Module +# 68| 0: [ReservedWord] module +# 68| 1: [Constant] Mod4 +# 69| 2: [Call] Call +# 69| 0: [Identifier] include +# 69| 1: [ArgumentList] ArgumentList +# 69| 0: [Constant] Mod1 +# 70| 3: [Module] Module +# 70| 0: [ReservedWord] module +# 70| 1: [ScopeResolution] ScopeResolution +# 70| 0: [Constant] Mod3 +# 70| 1: [ReservedWord] :: +# 70| 2: [Constant] Mod5 +# 71| 2: [Assignment] Assignment +# 71| 0: [Constant] FOURTY_SIX +# 71| 1: [ReservedWord] = +# 71| 2: [Integer] 46 +# 72| 3: [ReservedWord] end +# 73| 4: [Assignment] Assignment +# 73| 0: [ClassVariable] @@fourty_six +# 73| 1: [ReservedWord] = +# 73| 2: [ScopeResolution] ScopeResolution +# 73| 0: [Constant] Mod3 +# 73| 1: [ReservedWord] :: +# 73| 2: [Constant] FOURTY_SIX +# 74| 5: [ReservedWord] end +# 26| [Comment] # A call to Kernel::Array; despite beginning with an upper-case character, +# 27| [Comment] # we don't consider this to be a constant access. +# 55| [Comment] # refers to ::ModuleA::FOURTY_FOUR +# 57| [Comment] # refers to ::ModuleA::ModuleB::ClassB::FOURTY_FOUR +control/cases.rb: +# 1| [Program] Program +# 2| 0: [Assignment] Assignment +# 2| 0: [Identifier] a +# 2| 1: [ReservedWord] = +# 2| 2: [Integer] 0 +# 3| 1: [Assignment] Assignment +# 3| 0: [Identifier] b +# 3| 1: [ReservedWord] = +# 3| 2: [Integer] 0 +# 4| 2: [Assignment] Assignment +# 4| 0: [Identifier] c +# 4| 1: [ReservedWord] = +# 4| 2: [Integer] 0 +# 5| 3: [Assignment] Assignment +# 5| 0: [Identifier] d +# 5| 1: [ReservedWord] = +# 5| 2: [Integer] 0 +# 8| 4: [Case] Case +# 8| 0: [ReservedWord] case +# 8| 1: [Identifier] a +# 9| 2: [When] When +# 9| 0: [ReservedWord] when +# 9| 1: [Pattern] Pattern +# 9| 0: [Identifier] b +# 9| 2: [Then] Then +# 10| 0: [Integer] 100 +# 11| 3: [When] When +# 11| 0: [ReservedWord] when +# 11| 1: [Pattern] Pattern +# 11| 0: [Identifier] c +# 11| 2: [ReservedWord] , +# 11| 3: [Pattern] Pattern +# 11| 0: [Identifier] d +# 11| 4: [Then] Then +# 12| 0: [Integer] 200 +# 13| 4: [Else] Else +# 13| 0: [ReservedWord] else +# 14| 1: [Integer] 300 +# 15| 5: [ReservedWord] end +# 18| 5: [Case] Case +# 18| 0: [ReservedWord] case +# 19| 1: [When] When +# 19| 0: [ReservedWord] when +# 19| 1: [Pattern] Pattern +# 19| 0: [Binary] Binary +# 19| 0: [Identifier] a +# 19| 1: [ReservedWord] > +# 19| 2: [Identifier] b +# 19| 2: [Then] Then +# 19| 0: [ReservedWord] then +# 19| 1: [Integer] 10 +# 20| 2: [When] When +# 20| 0: [ReservedWord] when +# 20| 1: [Pattern] Pattern +# 20| 0: [Binary] Binary +# 20| 0: [Identifier] a +# 20| 1: [ReservedWord] == +# 20| 2: [Identifier] b +# 20| 2: [Then] Then +# 20| 0: [ReservedWord] then +# 20| 1: [Integer] 20 +# 21| 3: [When] When +# 21| 0: [ReservedWord] when +# 21| 1: [Pattern] Pattern +# 21| 0: [Binary] Binary +# 21| 0: [Identifier] a +# 21| 1: [ReservedWord] < +# 21| 2: [Identifier] b +# 21| 2: [Then] Then +# 21| 0: [ReservedWord] then +# 21| 1: [Integer] 30 +# 22| 4: [ReservedWord] end +# 26| 6: [CaseMatch] CaseMatch +# 26| 0: [ReservedWord] case +# 26| 1: [Identifier] expr +# 27| 2: [InClause] InClause +# 27| 0: [ReservedWord] in +# 27| 1: [Integer] 5 +# 27| 2: [Then] Then +# 27| 0: [ReservedWord] then +# 27| 1: [True] true +# 28| 3: [Else] Else +# 28| 0: [ReservedWord] else +# 28| 1: [False] false +# 29| 4: [ReservedWord] end +# 31| 7: [CaseMatch] CaseMatch +# 31| 0: [ReservedWord] case +# 31| 1: [Identifier] expr +# 32| 2: [InClause] InClause +# 32| 0: [ReservedWord] in +# 32| 1: [Identifier] x +# 32| 2: [UnlessGuard] UnlessGuard +# 32| 0: [ReservedWord] unless +# 32| 1: [Binary] Binary +# 32| 0: [Identifier] x +# 32| 1: [ReservedWord] < +# 32| 2: [Integer] 0 +# 32| 3: [Then] Then +# 33| 0: [ReservedWord] then +# 33| 1: [True] true +# 34| 3: [InClause] InClause +# 34| 0: [ReservedWord] in +# 34| 1: [Identifier] x +# 34| 2: [IfGuard] IfGuard +# 34| 0: [ReservedWord] if +# 34| 1: [Binary] Binary +# 34| 0: [Identifier] x +# 34| 1: [ReservedWord] < +# 34| 2: [Integer] 0 +# 34| 3: [Then] Then +# 35| 0: [ReservedWord] then +# 35| 1: [True] true +# 36| 4: [Else] Else +# 36| 0: [ReservedWord] else +# 36| 1: [False] false +# 37| 5: [ReservedWord] end +# 39| 8: [CaseMatch] CaseMatch +# 39| 0: [ReservedWord] case +# 39| 1: [Identifier] expr +# 40| 2: [InClause] InClause +# 40| 0: [ReservedWord] in +# 40| 1: [Integer] 5 +# 41| 3: [InClause] InClause +# 41| 0: [ReservedWord] in +# 41| 1: [ArrayPattern] ArrayPattern +# 41| 0: [Integer] 5 +# 41| 1: [SplatParameter] SplatParameter +# 42| 4: [InClause] InClause +# 42| 0: [ReservedWord] in +# 42| 1: [ArrayPattern] ArrayPattern +# 42| 0: [Integer] 1 +# 42| 1: [ReservedWord] , +# 42| 2: [Integer] 2 +# 43| 5: [InClause] InClause +# 43| 0: [ReservedWord] in +# 43| 1: [ArrayPattern] ArrayPattern +# 43| 0: [Integer] 1 +# 43| 1: [ReservedWord] , +# 43| 2: [Integer] 2 +# 43| 3: [SplatParameter] SplatParameter +# 44| 6: [InClause] InClause +# 44| 0: [ReservedWord] in +# 44| 1: [ArrayPattern] ArrayPattern +# 44| 0: [Integer] 1 +# 44| 1: [ReservedWord] , +# 44| 2: [Integer] 2 +# 44| 3: [ReservedWord] , +# 44| 4: [Integer] 3 +# 45| 7: [InClause] InClause +# 45| 0: [ReservedWord] in +# 45| 1: [ArrayPattern] ArrayPattern +# 45| 0: [Integer] 1 +# 45| 1: [ReservedWord] , +# 45| 2: [Integer] 2 +# 45| 3: [ReservedWord] , +# 45| 4: [Integer] 3 +# 45| 5: [SplatParameter] SplatParameter +# 46| 8: [InClause] InClause +# 46| 0: [ReservedWord] in +# 46| 1: [ArrayPattern] ArrayPattern +# 46| 0: [Integer] 1 +# 46| 1: [ReservedWord] , +# 46| 2: [Integer] 2 +# 46| 3: [ReservedWord] , +# 46| 4: [Integer] 3 +# 46| 5: [ReservedWord] , +# 46| 6: [SplatParameter] SplatParameter +# 46| 0: [ReservedWord] * +# 47| 9: [InClause] InClause +# 47| 0: [ReservedWord] in +# 47| 1: [ArrayPattern] ArrayPattern +# 47| 0: [Integer] 1 +# 47| 1: [ReservedWord] , +# 47| 2: [SplatParameter] SplatParameter +# 47| 0: [ReservedWord] * +# 47| 1: [Identifier] x +# 47| 3: [ReservedWord] , +# 47| 4: [Integer] 3 +# 48| 10: [InClause] InClause +# 48| 0: [ReservedWord] in +# 48| 1: [ArrayPattern] ArrayPattern +# 48| 0: [SplatParameter] SplatParameter +# 48| 0: [ReservedWord] * +# 49| 11: [InClause] InClause +# 49| 0: [ReservedWord] in +# 49| 1: [ArrayPattern] ArrayPattern +# 49| 0: [SplatParameter] SplatParameter +# 49| 0: [ReservedWord] * +# 49| 1: [ReservedWord] , +# 49| 2: [Integer] 3 +# 49| 3: [ReservedWord] , +# 49| 4: [Integer] 4 +# 50| 12: [InClause] InClause +# 50| 0: [ReservedWord] in +# 50| 1: [FindPattern] FindPattern +# 50| 0: [SplatParameter] SplatParameter +# 50| 0: [ReservedWord] * +# 50| 1: [ReservedWord] , +# 50| 2: [Integer] 3 +# 50| 3: [ReservedWord] , +# 50| 4: [SplatParameter] SplatParameter +# 50| 0: [ReservedWord] * +# 51| 13: [InClause] InClause +# 51| 0: [ReservedWord] in +# 51| 1: [FindPattern] FindPattern +# 51| 0: [SplatParameter] SplatParameter +# 51| 0: [ReservedWord] * +# 51| 1: [Identifier] a +# 51| 1: [ReservedWord] , +# 51| 2: [Integer] 3 +# 51| 3: [ReservedWord] , +# 51| 4: [SplatParameter] SplatParameter +# 51| 0: [ReservedWord] * +# 51| 1: [Identifier] b +# 52| 14: [InClause] InClause +# 52| 0: [ReservedWord] in +# 52| 1: [HashPattern] HashPattern +# 52| 0: [KeywordPattern] KeywordPattern +# 52| 0: [HashKeySymbol] a +# 52| 1: [ReservedWord] : +# 53| 15: [InClause] InClause +# 53| 0: [ReservedWord] in +# 53| 1: [HashPattern] HashPattern +# 53| 0: [KeywordPattern] KeywordPattern +# 53| 0: [HashKeySymbol] a +# 53| 1: [ReservedWord] : +# 53| 2: [Integer] 5 +# 54| 16: [InClause] InClause +# 54| 0: [ReservedWord] in +# 54| 1: [HashPattern] HashPattern +# 54| 0: [KeywordPattern] KeywordPattern +# 54| 0: [HashKeySymbol] a +# 54| 1: [ReservedWord] : +# 54| 2: [Integer] 5 +# 54| 1: [ReservedWord] , +# 55| 17: [InClause] InClause +# 55| 0: [ReservedWord] in +# 55| 1: [HashPattern] HashPattern +# 55| 0: [KeywordPattern] KeywordPattern +# 55| 0: [HashKeySymbol] a +# 55| 1: [ReservedWord] : +# 55| 2: [Integer] 5 +# 55| 1: [ReservedWord] , +# 55| 2: [KeywordPattern] KeywordPattern +# 55| 0: [HashKeySymbol] b +# 55| 1: [ReservedWord] : +# 55| 3: [ReservedWord] , +# 55| 4: [HashSplatParameter] HashSplatParameter +# 55| 0: [ReservedWord] ** +# 56| 18: [InClause] InClause +# 56| 0: [ReservedWord] in +# 56| 1: [HashPattern] HashPattern +# 56| 0: [KeywordPattern] KeywordPattern +# 56| 0: [HashKeySymbol] a +# 56| 1: [ReservedWord] : +# 56| 2: [Integer] 5 +# 56| 1: [ReservedWord] , +# 56| 2: [KeywordPattern] KeywordPattern +# 56| 0: [HashKeySymbol] b +# 56| 1: [ReservedWord] : +# 56| 3: [ReservedWord] , +# 56| 4: [HashSplatParameter] HashSplatParameter +# 56| 0: [ReservedWord] ** +# 56| 1: [Identifier] map +# 57| 19: [InClause] InClause +# 57| 0: [ReservedWord] in +# 57| 1: [HashPattern] HashPattern +# 57| 0: [KeywordPattern] KeywordPattern +# 57| 0: [HashKeySymbol] a +# 57| 1: [ReservedWord] : +# 57| 2: [Integer] 5 +# 57| 1: [ReservedWord] , +# 57| 2: [KeywordPattern] KeywordPattern +# 57| 0: [HashKeySymbol] b +# 57| 1: [ReservedWord] : +# 57| 3: [ReservedWord] , +# 57| 4: [HashSplatNil] **nil +# 57| 0: [ReservedWord] ** +# 57| 1: [ReservedWord] nil +# 58| 20: [InClause] InClause +# 58| 0: [ReservedWord] in +# 58| 1: [HashPattern] HashPattern +# 58| 0: [HashSplatNil] **nil +# 58| 0: [ReservedWord] ** +# 58| 1: [ReservedWord] nil +# 59| 21: [InClause] InClause +# 59| 0: [ReservedWord] in +# 59| 1: [ArrayPattern] ArrayPattern +# 59| 0: [ReservedWord] [ +# 59| 1: [Integer] 5 +# 59| 2: [ReservedWord] ] +# 60| 22: [InClause] InClause +# 60| 0: [ReservedWord] in +# 60| 1: [ArrayPattern] ArrayPattern +# 60| 0: [ReservedWord] [ +# 60| 1: [Integer] 5 +# 60| 2: [SplatParameter] SplatParameter +# 60| 3: [ReservedWord] ] +# 61| 23: [InClause] InClause +# 61| 0: [ReservedWord] in +# 61| 1: [ArrayPattern] ArrayPattern +# 61| 0: [ReservedWord] [ +# 61| 1: [Integer] 1 +# 61| 2: [ReservedWord] , +# 61| 3: [Integer] 2 +# 61| 4: [ReservedWord] ] +# 62| 24: [InClause] InClause +# 62| 0: [ReservedWord] in +# 62| 1: [ArrayPattern] ArrayPattern +# 62| 0: [ReservedWord] [ +# 62| 1: [Integer] 1 +# 62| 2: [ReservedWord] , +# 62| 3: [Integer] 2 +# 62| 4: [SplatParameter] SplatParameter +# 62| 5: [ReservedWord] ] +# 63| 25: [InClause] InClause +# 63| 0: [ReservedWord] in +# 63| 1: [ArrayPattern] ArrayPattern +# 63| 0: [ReservedWord] [ +# 63| 1: [Integer] 1 +# 63| 2: [ReservedWord] , +# 63| 3: [Integer] 2 +# 63| 4: [ReservedWord] , +# 63| 5: [Integer] 3 +# 63| 6: [ReservedWord] ] +# 64| 26: [InClause] InClause +# 64| 0: [ReservedWord] in +# 64| 1: [ArrayPattern] ArrayPattern +# 64| 0: [ReservedWord] [ +# 64| 1: [Integer] 1 +# 64| 2: [ReservedWord] , +# 64| 3: [Integer] 2 +# 64| 4: [ReservedWord] , +# 64| 5: [Integer] 3 +# 64| 6: [SplatParameter] SplatParameter +# 64| 7: [ReservedWord] ] +# 65| 27: [InClause] InClause +# 65| 0: [ReservedWord] in +# 65| 1: [ArrayPattern] ArrayPattern +# 65| 0: [ReservedWord] [ +# 65| 1: [Integer] 1 +# 65| 2: [ReservedWord] , +# 65| 3: [Integer] 2 +# 65| 4: [ReservedWord] , +# 65| 5: [Integer] 3 +# 65| 6: [ReservedWord] , +# 65| 7: [SplatParameter] SplatParameter +# 65| 0: [ReservedWord] * +# 65| 8: [ReservedWord] ] +# 66| 28: [InClause] InClause +# 66| 0: [ReservedWord] in +# 66| 1: [ArrayPattern] ArrayPattern +# 66| 0: [ReservedWord] [ +# 66| 1: [Integer] 1 +# 66| 2: [ReservedWord] , +# 66| 3: [SplatParameter] SplatParameter +# 66| 0: [ReservedWord] * +# 66| 1: [Identifier] x +# 66| 4: [ReservedWord] , +# 66| 5: [Integer] 3 +# 66| 6: [ReservedWord] ] +# 67| 29: [InClause] InClause +# 67| 0: [ReservedWord] in +# 67| 1: [ArrayPattern] ArrayPattern +# 67| 0: [ReservedWord] [ +# 67| 1: [SplatParameter] SplatParameter +# 67| 0: [ReservedWord] * +# 67| 2: [ReservedWord] ] +# 68| 30: [InClause] InClause +# 68| 0: [ReservedWord] in +# 68| 1: [ArrayPattern] ArrayPattern +# 68| 0: [ReservedWord] [ +# 68| 1: [SplatParameter] SplatParameter +# 68| 0: [ReservedWord] * +# 68| 1: [Identifier] x +# 68| 2: [ReservedWord] , +# 68| 3: [Integer] 3 +# 68| 4: [ReservedWord] , +# 68| 5: [Integer] 4 +# 68| 6: [ReservedWord] ] +# 69| 31: [InClause] InClause +# 69| 0: [ReservedWord] in +# 69| 1: [FindPattern] FindPattern +# 69| 0: [ReservedWord] [ +# 69| 1: [SplatParameter] SplatParameter +# 69| 0: [ReservedWord] * +# 69| 2: [ReservedWord] , +# 69| 3: [Integer] 3 +# 69| 4: [ReservedWord] , +# 69| 5: [SplatParameter] SplatParameter +# 69| 0: [ReservedWord] * +# 69| 6: [ReservedWord] ] +# 70| 32: [InClause] InClause +# 70| 0: [ReservedWord] in +# 70| 1: [FindPattern] FindPattern +# 70| 0: [ReservedWord] [ +# 70| 1: [SplatParameter] SplatParameter +# 70| 0: [ReservedWord] * +# 70| 1: [Identifier] a +# 70| 2: [ReservedWord] , +# 70| 3: [Integer] 3 +# 70| 4: [ReservedWord] , +# 70| 5: [SplatParameter] SplatParameter +# 70| 0: [ReservedWord] * +# 70| 1: [Identifier] b +# 70| 6: [ReservedWord] ] +# 71| 33: [InClause] InClause +# 71| 0: [ReservedWord] in +# 71| 1: [HashPattern] HashPattern +# 71| 0: [ReservedWord] { +# 71| 1: [KeywordPattern] KeywordPattern +# 71| 0: [HashKeySymbol] a +# 71| 1: [ReservedWord] : +# 71| 2: [ReservedWord] } +# 72| 34: [InClause] InClause +# 72| 0: [ReservedWord] in +# 72| 1: [HashPattern] HashPattern +# 72| 0: [ReservedWord] { +# 72| 1: [KeywordPattern] KeywordPattern +# 72| 0: [HashKeySymbol] a +# 72| 1: [ReservedWord] : +# 72| 2: [Integer] 5 +# 72| 2: [ReservedWord] } +# 73| 35: [InClause] InClause +# 73| 0: [ReservedWord] in +# 73| 1: [HashPattern] HashPattern +# 73| 0: [ReservedWord] { +# 73| 1: [KeywordPattern] KeywordPattern +# 73| 0: [HashKeySymbol] a +# 73| 1: [ReservedWord] : +# 73| 2: [Integer] 5 +# 73| 2: [ReservedWord] , +# 73| 3: [ReservedWord] } +# 74| 36: [InClause] InClause +# 74| 0: [ReservedWord] in +# 74| 1: [HashPattern] HashPattern +# 74| 0: [ReservedWord] { +# 74| 1: [KeywordPattern] KeywordPattern +# 74| 0: [HashKeySymbol] a +# 74| 1: [ReservedWord] : +# 74| 2: [Integer] 5 +# 74| 2: [ReservedWord] , +# 74| 3: [KeywordPattern] KeywordPattern +# 74| 0: [HashKeySymbol] b +# 74| 1: [ReservedWord] : +# 74| 4: [ReservedWord] , +# 74| 5: [HashSplatParameter] HashSplatParameter +# 74| 0: [ReservedWord] ** +# 74| 6: [ReservedWord] } +# 75| 37: [InClause] InClause +# 75| 0: [ReservedWord] in +# 75| 1: [HashPattern] HashPattern +# 75| 0: [ReservedWord] { +# 75| 1: [KeywordPattern] KeywordPattern +# 75| 0: [HashKeySymbol] a +# 75| 1: [ReservedWord] : +# 75| 2: [Integer] 5 +# 75| 2: [ReservedWord] , +# 75| 3: [KeywordPattern] KeywordPattern +# 75| 0: [HashKeySymbol] b +# 75| 1: [ReservedWord] : +# 75| 4: [ReservedWord] , +# 75| 5: [HashSplatParameter] HashSplatParameter +# 75| 0: [ReservedWord] ** +# 75| 1: [Identifier] map +# 75| 6: [ReservedWord] } +# 76| 38: [InClause] InClause +# 76| 0: [ReservedWord] in +# 76| 1: [HashPattern] HashPattern +# 76| 0: [ReservedWord] { +# 76| 1: [KeywordPattern] KeywordPattern +# 76| 0: [HashKeySymbol] a +# 76| 1: [ReservedWord] : +# 76| 2: [Integer] 5 +# 76| 2: [ReservedWord] , +# 76| 3: [KeywordPattern] KeywordPattern +# 76| 0: [HashKeySymbol] b +# 76| 1: [ReservedWord] : +# 76| 4: [ReservedWord] , +# 76| 5: [HashSplatNil] **nil +# 76| 0: [ReservedWord] ** +# 76| 1: [ReservedWord] nil +# 76| 6: [ReservedWord] } +# 77| 39: [InClause] InClause +# 77| 0: [ReservedWord] in +# 77| 1: [HashPattern] HashPattern +# 77| 0: [ReservedWord] { +# 77| 1: [HashSplatNil] **nil +# 77| 0: [ReservedWord] ** +# 77| 1: [ReservedWord] nil +# 77| 2: [ReservedWord] } +# 78| 40: [InClause] InClause +# 78| 0: [ReservedWord] in +# 78| 1: [HashPattern] HashPattern +# 78| 0: [ReservedWord] { +# 78| 1: [ReservedWord] } +# 79| 41: [InClause] InClause +# 79| 0: [ReservedWord] in +# 79| 1: [ArrayPattern] ArrayPattern +# 79| 0: [ReservedWord] [ +# 79| 1: [ReservedWord] ] +# 80| 42: [ReservedWord] end +# 84| 9: [Assignment] Assignment +# 84| 0: [Identifier] foo +# 84| 1: [ReservedWord] = +# 84| 2: [Integer] 42 +# 86| 10: [CaseMatch] CaseMatch +# 86| 0: [ReservedWord] case +# 86| 1: [Identifier] expr +# 87| 2: [InClause] InClause +# 87| 0: [ReservedWord] in +# 87| 1: [Integer] 5 +# 88| 3: [InClause] InClause +# 88| 0: [ReservedWord] in +# 88| 1: [VariableReferencePattern] VariableReferencePattern +# 88| 0: [ReservedWord] ^ +# 88| 1: [Identifier] foo +# 89| 4: [InClause] InClause +# 89| 0: [ReservedWord] in +# 89| 1: [String] String +# 89| 0: [ReservedWord] " +# 89| 1: [StringContent] string +# 89| 2: [ReservedWord] " +# 90| 5: [InClause] InClause +# 90| 0: [ReservedWord] in +# 90| 1: [StringArray] StringArray +# 90| 0: [ReservedWord] %w( +# 90| 1: [BareString] BareString +# 90| 0: [StringContent] foo +# 90| 2: [BareString] BareString +# 90| 0: [StringContent] bar +# 90| 3: [ReservedWord] ) +# 91| 6: [InClause] InClause +# 91| 0: [ReservedWord] in +# 91| 1: [SymbolArray] SymbolArray +# 91| 0: [ReservedWord] %i( +# 91| 1: [BareSymbol] BareSymbol +# 91| 0: [StringContent] foo +# 91| 2: [BareSymbol] BareSymbol +# 91| 0: [StringContent] bar +# 91| 3: [ReservedWord] ) +# 92| 7: [InClause] InClause +# 92| 0: [ReservedWord] in +# 92| 1: [Regex] Regex +# 92| 0: [ReservedWord] / +# 92| 1: [StringContent] .*abc[0-9] +# 92| 2: [ReservedWord] / +# 93| 8: [InClause] InClause +# 93| 0: [ReservedWord] in +# 93| 1: [Range] Range +# 93| 0: [Integer] 5 +# 93| 1: [ReservedWord] .. +# 93| 2: [Integer] 10 +# 94| 9: [InClause] InClause +# 94| 0: [ReservedWord] in +# 94| 1: [Range] Range +# 94| 0: [ReservedWord] .. +# 94| 1: [Integer] 10 +# 95| 10: [InClause] InClause +# 95| 0: [ReservedWord] in +# 95| 1: [Range] Range +# 95| 0: [Integer] 5 +# 95| 1: [ReservedWord] .. +# 96| 11: [InClause] InClause +# 96| 0: [ReservedWord] in +# 96| 1: [AsPattern] AsPattern +# 96| 0: [Integer] 5 +# 96| 1: [ReservedWord] => +# 96| 2: [Identifier] x +# 97| 12: [InClause] InClause +# 97| 0: [ReservedWord] in +# 97| 1: [Constant] Foo +# 98| 13: [InClause] InClause +# 98| 0: [ReservedWord] in +# 98| 1: [ScopeResolution] ScopeResolution +# 98| 0: [Constant] Foo +# 98| 1: [ReservedWord] :: +# 98| 2: [Constant] Bar +# 99| 14: [InClause] InClause +# 99| 0: [ReservedWord] in +# 99| 1: [ScopeResolution] ScopeResolution +# 99| 0: [ScopeResolution] ScopeResolution +# 99| 0: [ReservedWord] :: +# 99| 1: [Constant] Foo +# 99| 1: [ReservedWord] :: +# 99| 2: [Constant] Bar +# 100| 15: [InClause] InClause +# 100| 0: [ReservedWord] in +# 100| 1: [AlternativePattern] AlternativePattern +# 100| 0: [Nil] nil +# 100| 1: [ReservedWord] | +# 100| 2: [Self] self +# 100| 3: [ReservedWord] | +# 100| 4: [True] true +# 100| 5: [ReservedWord] | +# 100| 6: [False] false +# 100| 7: [ReservedWord] | +# 100| 8: [Line] __LINE__ +# 100| 9: [ReservedWord] | +# 100| 10: [File] __FILE__ +# 100| 11: [ReservedWord] | +# 100| 12: [Encoding] __ENCODING__ +# 101| 16: [InClause] InClause +# 101| 0: [ReservedWord] in +# 101| 1: [Lambda] Lambda +# 101| 0: [ReservedWord] -> +# 101| 1: [LambdaParameters] LambdaParameters +# 101| 0: [Identifier] x +# 101| 2: [Block] Block +# 101| 0: [ReservedWord] { +# 101| 1: [Binary] Binary +# 101| 0: [Identifier] x +# 101| 1: [ReservedWord] == +# 101| 2: [Integer] 10 +# 101| 2: [ReservedWord] } +# 102| 17: [InClause] InClause +# 102| 0: [ReservedWord] in +# 102| 1: [SimpleSymbol] :foo +# 103| 18: [InClause] InClause +# 103| 0: [ReservedWord] in +# 103| 1: [DelimitedSymbol] DelimitedSymbol +# 103| 0: [ReservedWord] :" +# 103| 1: [StringContent] foo bar +# 103| 2: [ReservedWord] " +# 104| 19: [InClause] InClause +# 104| 0: [ReservedWord] in +# 104| 1: [AlternativePattern] AlternativePattern +# 104| 0: [Unary] Unary +# 104| 0: [ReservedWord] - +# 104| 1: [Integer] 5 +# 104| 1: [ReservedWord] | +# 104| 2: [Unary] Unary +# 104| 0: [ReservedWord] + +# 104| 1: [Integer] 10 +# 105| 20: [InClause] InClause +# 105| 0: [ReservedWord] in +# 105| 1: [ParenthesizedPattern] ParenthesizedPattern +# 105| 0: [ReservedWord] ( +# 105| 1: [Range] Range +# 105| 0: [Integer] 1 +# 105| 1: [ReservedWord] .. +# 105| 2: [ReservedWord] ) +# 106| 21: [InClause] InClause +# 106| 0: [ReservedWord] in +# 106| 1: [ParenthesizedPattern] ParenthesizedPattern +# 106| 0: [ReservedWord] ( +# 106| 1: [AlternativePattern] AlternativePattern +# 106| 0: [Integer] 0 +# 106| 1: [ReservedWord] | +# 106| 2: [String] String +# 106| 0: [ReservedWord] " +# 106| 1: [ReservedWord] " +# 106| 3: [ReservedWord] | +# 106| 4: [ArrayPattern] ArrayPattern +# 106| 0: [ReservedWord] [ +# 106| 1: [ReservedWord] ] +# 106| 5: [ReservedWord] | +# 106| 6: [HashPattern] HashPattern +# 106| 0: [ReservedWord] { +# 106| 1: [ReservedWord] } +# 106| 2: [ReservedWord] ) +# 107| 22: [InClause] InClause +# 107| 0: [ReservedWord] in +# 107| 1: [Identifier] var +# 108| 23: [ReservedWord] end +# 110| 11: [CaseMatch] CaseMatch +# 110| 0: [ReservedWord] case +# 110| 1: [Identifier] expr +# 111| 2: [InClause] InClause +# 111| 0: [ReservedWord] in +# 111| 1: [AlternativePattern] AlternativePattern +# 111| 0: [Integer] 5 +# 111| 1: [ReservedWord] | +# 111| 2: [VariableReferencePattern] VariableReferencePattern +# 111| 0: [ReservedWord] ^ +# 111| 1: [Identifier] foo +# 111| 3: [ReservedWord] | +# 111| 4: [String] String +# 111| 0: [ReservedWord] " +# 111| 1: [StringContent] string +# 111| 2: [ReservedWord] " +# 111| 5: [ReservedWord] | +# 111| 6: [Identifier] var +# 112| 3: [ReservedWord] end +# 116| 12: [CaseMatch] CaseMatch +# 116| 0: [ReservedWord] case +# 116| 1: [Identifier] expr +# 117| 2: [InClause] InClause +# 117| 0: [ReservedWord] in +# 117| 1: [ArrayPattern] ArrayPattern +# 117| 0: [ReservedWord] [ +# 117| 1: [ReservedWord] ] +# 117| 2: [ReservedWord] ; +# 118| 3: [InClause] InClause +# 118| 0: [ReservedWord] in +# 118| 1: [ArrayPattern] ArrayPattern +# 118| 0: [ReservedWord] [ +# 118| 1: [Identifier] x +# 118| 2: [ReservedWord] ] +# 118| 2: [ReservedWord] ; +# 119| 4: [InClause] InClause +# 119| 0: [ReservedWord] in +# 119| 1: [ArrayPattern] ArrayPattern +# 119| 0: [ReservedWord] [ +# 119| 1: [Identifier] x +# 119| 2: [SplatParameter] SplatParameter +# 119| 3: [ReservedWord] ] +# 119| 2: [ReservedWord] ; +# 120| 5: [InClause] InClause +# 120| 0: [ReservedWord] in +# 120| 1: [ArrayPattern] ArrayPattern +# 120| 0: [ScopeResolution] ScopeResolution +# 120| 0: [Constant] Foo +# 120| 1: [ReservedWord] :: +# 120| 2: [Constant] Bar +# 120| 1: [ReservedWord] [ +# 120| 2: [ReservedWord] ] +# 120| 2: [ReservedWord] ; +# 121| 6: [InClause] InClause +# 121| 0: [ReservedWord] in +# 121| 1: [ArrayPattern] ArrayPattern +# 121| 0: [Constant] Foo +# 121| 1: [ReservedWord] ( +# 121| 2: [ReservedWord] ) +# 121| 2: [ReservedWord] ; +# 122| 7: [InClause] InClause +# 122| 0: [ReservedWord] in +# 122| 1: [ArrayPattern] ArrayPattern +# 122| 0: [Constant] Bar +# 122| 1: [ReservedWord] ( +# 122| 2: [SplatParameter] SplatParameter +# 122| 0: [ReservedWord] * +# 122| 3: [ReservedWord] ) +# 122| 2: [ReservedWord] ; +# 123| 8: [InClause] InClause +# 123| 0: [ReservedWord] in +# 123| 1: [ArrayPattern] ArrayPattern +# 123| 0: [Constant] Bar +# 123| 1: [ReservedWord] ( +# 123| 2: [Identifier] a +# 123| 3: [ReservedWord] , +# 123| 4: [Identifier] b +# 123| 5: [ReservedWord] , +# 123| 6: [SplatParameter] SplatParameter +# 123| 0: [ReservedWord] * +# 123| 1: [Identifier] c +# 123| 7: [ReservedWord] , +# 123| 8: [Identifier] d +# 123| 9: [ReservedWord] , +# 123| 10: [Identifier] e +# 123| 11: [ReservedWord] ) +# 123| 2: [ReservedWord] ; +# 124| 9: [ReservedWord] end +# 128| 13: [CaseMatch] CaseMatch +# 128| 0: [ReservedWord] case +# 128| 1: [Identifier] expr +# 129| 2: [InClause] InClause +# 129| 0: [ReservedWord] in +# 129| 1: [FindPattern] FindPattern +# 129| 0: [ReservedWord] [ +# 129| 1: [SplatParameter] SplatParameter +# 129| 0: [ReservedWord] * +# 129| 2: [ReservedWord] , +# 129| 3: [Identifier] x +# 129| 4: [ReservedWord] , +# 129| 5: [SplatParameter] SplatParameter +# 129| 0: [ReservedWord] * +# 129| 6: [ReservedWord] ] +# 129| 2: [ReservedWord] ; +# 130| 3: [InClause] InClause +# 130| 0: [ReservedWord] in +# 130| 1: [FindPattern] FindPattern +# 130| 0: [ReservedWord] [ +# 130| 1: [SplatParameter] SplatParameter +# 130| 0: [ReservedWord] * +# 130| 1: [Identifier] x +# 130| 2: [ReservedWord] , +# 130| 3: [Integer] 1 +# 130| 4: [ReservedWord] , +# 130| 5: [Integer] 2 +# 130| 6: [ReservedWord] , +# 130| 7: [SplatParameter] SplatParameter +# 130| 0: [ReservedWord] * +# 130| 1: [Identifier] y +# 130| 8: [ReservedWord] ] +# 130| 2: [ReservedWord] ; +# 131| 4: [InClause] InClause +# 131| 0: [ReservedWord] in +# 131| 1: [FindPattern] FindPattern +# 131| 0: [ScopeResolution] ScopeResolution +# 131| 0: [Constant] Foo +# 131| 1: [ReservedWord] :: +# 131| 2: [Constant] Bar +# 131| 1: [ReservedWord] [ +# 131| 2: [SplatParameter] SplatParameter +# 131| 0: [ReservedWord] * +# 131| 3: [ReservedWord] , +# 131| 4: [Integer] 1 +# 131| 5: [ReservedWord] , +# 131| 6: [SplatParameter] SplatParameter +# 131| 0: [ReservedWord] * +# 131| 7: [ReservedWord] ] +# 131| 2: [ReservedWord] ; +# 132| 5: [InClause] InClause +# 132| 0: [ReservedWord] in +# 132| 1: [FindPattern] FindPattern +# 132| 0: [Constant] Foo +# 132| 1: [ReservedWord] ( +# 132| 2: [SplatParameter] SplatParameter +# 132| 0: [ReservedWord] * +# 132| 3: [ReservedWord] , +# 132| 4: [Constant] Bar +# 132| 5: [ReservedWord] , +# 132| 6: [SplatParameter] SplatParameter +# 132| 0: [ReservedWord] * +# 132| 7: [ReservedWord] ) +# 132| 2: [ReservedWord] ; +# 133| 6: [ReservedWord] end +# 137| 14: [CaseMatch] CaseMatch +# 137| 0: [ReservedWord] case +# 137| 1: [Identifier] expr +# 138| 2: [InClause] InClause +# 138| 0: [ReservedWord] in +# 138| 1: [HashPattern] HashPattern +# 138| 0: [ReservedWord] { +# 138| 1: [ReservedWord] } +# 138| 2: [ReservedWord] ; +# 139| 3: [InClause] InClause +# 139| 0: [ReservedWord] in +# 139| 1: [HashPattern] HashPattern +# 139| 0: [ReservedWord] { +# 139| 1: [KeywordPattern] KeywordPattern +# 139| 0: [HashKeySymbol] x +# 139| 1: [ReservedWord] : +# 139| 2: [ReservedWord] } +# 139| 2: [ReservedWord] ; +# 140| 4: [InClause] InClause +# 140| 0: [ReservedWord] in +# 140| 1: [HashPattern] HashPattern +# 140| 0: [ScopeResolution] ScopeResolution +# 140| 0: [Constant] Foo +# 140| 1: [ReservedWord] :: +# 140| 2: [Constant] Bar +# 140| 1: [ReservedWord] [ +# 140| 2: [KeywordPattern] KeywordPattern +# 140| 0: [HashKeySymbol] x +# 140| 1: [ReservedWord] : +# 140| 2: [Integer] 1 +# 140| 3: [ReservedWord] ] +# 140| 2: [ReservedWord] ; +# 141| 5: [InClause] InClause +# 141| 0: [ReservedWord] in +# 141| 1: [HashPattern] HashPattern +# 141| 0: [ScopeResolution] ScopeResolution +# 141| 0: [Constant] Foo +# 141| 1: [ReservedWord] :: +# 141| 2: [Constant] Bar +# 141| 1: [ReservedWord] [ +# 141| 2: [KeywordPattern] KeywordPattern +# 141| 0: [HashKeySymbol] x +# 141| 1: [ReservedWord] : +# 141| 2: [Integer] 1 +# 141| 3: [ReservedWord] , +# 141| 4: [KeywordPattern] KeywordPattern +# 141| 0: [HashKeySymbol] a +# 141| 1: [ReservedWord] : +# 141| 5: [ReservedWord] , +# 141| 6: [HashSplatParameter] HashSplatParameter +# 141| 0: [ReservedWord] ** +# 141| 1: [Identifier] rest +# 141| 7: [ReservedWord] ] +# 141| 2: [ReservedWord] ; +# 142| 6: [InClause] InClause +# 142| 0: [ReservedWord] in +# 142| 1: [HashPattern] HashPattern +# 142| 0: [Constant] Foo +# 142| 1: [ReservedWord] ( +# 142| 2: [KeywordPattern] KeywordPattern +# 142| 0: [HashKeySymbol] y +# 142| 1: [ReservedWord] : +# 142| 3: [ReservedWord] ) +# 142| 2: [ReservedWord] ; +# 143| 7: [InClause] InClause +# 143| 0: [ReservedWord] in +# 143| 1: [HashPattern] HashPattern +# 143| 0: [Constant] Bar +# 143| 1: [ReservedWord] ( +# 143| 2: [HashSplatParameter] HashSplatParameter +# 143| 0: [ReservedWord] ** +# 143| 3: [ReservedWord] ) +# 143| 2: [ReservedWord] ; +# 144| 8: [InClause] InClause +# 144| 0: [ReservedWord] in +# 144| 1: [HashPattern] HashPattern +# 144| 0: [Constant] Bar +# 144| 1: [ReservedWord] ( +# 144| 2: [KeywordPattern] KeywordPattern +# 144| 0: [HashKeySymbol] a +# 144| 1: [ReservedWord] : +# 144| 2: [Integer] 1 +# 144| 3: [ReservedWord] , +# 144| 4: [HashSplatNil] **nil +# 144| 0: [ReservedWord] ** +# 144| 1: [ReservedWord] nil +# 144| 5: [ReservedWord] ) +# 144| 2: [ReservedWord] ; +# 145| 9: [ReservedWord] end +# 147| 15: [CaseMatch] CaseMatch +# 147| 0: [ReservedWord] case +# 147| 1: [Identifier] expr +# 148| 2: [InClause] InClause +# 148| 0: [ReservedWord] in +# 148| 1: [VariableReferencePattern] VariableReferencePattern +# 148| 0: [ReservedWord] ^ +# 148| 1: [Identifier] foo +# 148| 2: [ReservedWord] ; +# 149| 3: [InClause] InClause +# 149| 0: [ReservedWord] in +# 149| 1: [VariableReferencePattern] VariableReferencePattern +# 149| 0: [ReservedWord] ^ +# 149| 1: [GlobalVariable] $foo +# 149| 2: [ReservedWord] ; +# 150| 4: [InClause] InClause +# 150| 0: [ReservedWord] in +# 150| 1: [VariableReferencePattern] VariableReferencePattern +# 150| 0: [ReservedWord] ^ +# 150| 1: [InstanceVariable] @foo +# 150| 2: [ReservedWord] ; +# 151| 5: [InClause] InClause +# 151| 0: [ReservedWord] in +# 151| 1: [VariableReferencePattern] VariableReferencePattern +# 151| 0: [ReservedWord] ^ +# 151| 1: [ClassVariable] @@foo +# 151| 2: [ReservedWord] ; +# 152| 6: [ReservedWord] end +# 154| 16: [CaseMatch] CaseMatch +# 154| 0: [ReservedWord] case +# 154| 1: [Identifier] expr +# 155| 2: [InClause] InClause +# 155| 0: [ReservedWord] in +# 155| 1: [ExpressionReferencePattern] ExpressionReferencePattern +# 155| 0: [ReservedWord] ^ +# 155| 1: [ReservedWord] ( +# 155| 2: [Identifier] foo +# 155| 3: [ReservedWord] ) +# 155| 2: [ReservedWord] ; +# 156| 3: [InClause] InClause +# 156| 0: [ReservedWord] in +# 156| 1: [ExpressionReferencePattern] ExpressionReferencePattern +# 156| 0: [ReservedWord] ^ +# 156| 1: [ReservedWord] ( +# 156| 2: [InstanceVariable] @foo +# 156| 3: [ReservedWord] ) +# 156| 2: [ReservedWord] ; +# 157| 4: [InClause] InClause +# 157| 0: [ReservedWord] in +# 157| 1: [ExpressionReferencePattern] ExpressionReferencePattern +# 157| 0: [ReservedWord] ^ +# 157| 1: [ReservedWord] ( +# 157| 2: [Binary] Binary +# 157| 0: [Integer] 1 +# 157| 1: [ReservedWord] + +# 157| 2: [Integer] 1 +# 157| 3: [ReservedWord] ) +# 157| 2: [ReservedWord] ; +# 158| 5: [ReservedWord] end +# 1| [Comment] # Define some variables used below +# 7| [Comment] # A case expr with a value and an else branch +# 17| [Comment] # A case expr without a value or else branch +# 24| [Comment] # pattern matching +# 82| [Comment] # more pattern matching +# 114| [Comment] # array patterns +# 126| [Comment] # find patterns +# 135| [Comment] # hash patterns +control/conditionals.rb: +# 1| [Program] Program +# 2| 0: [Assignment] Assignment +# 2| 0: [Identifier] a +# 2| 1: [ReservedWord] = +# 2| 2: [Integer] 0 +# 3| 1: [Assignment] Assignment +# 3| 0: [Identifier] b +# 3| 1: [ReservedWord] = +# 3| 2: [Integer] 0 +# 4| 2: [Assignment] Assignment +# 4| 0: [Identifier] c +# 4| 1: [ReservedWord] = +# 4| 2: [Integer] 0 +# 5| 3: [Assignment] Assignment +# 5| 0: [Identifier] d +# 5| 1: [ReservedWord] = +# 5| 2: [Integer] 0 +# 6| 4: [Assignment] Assignment +# 6| 0: [Identifier] e +# 6| 1: [ReservedWord] = +# 6| 2: [Integer] 0 +# 7| 5: [Assignment] Assignment +# 7| 0: [Identifier] f +# 7| 1: [ReservedWord] = +# 7| 2: [Integer] 0 +# 10| 6: [If] If +# 10| 0: [ReservedWord] if +# 10| 1: [Binary] Binary +# 10| 0: [Identifier] a +# 10| 1: [ReservedWord] > +# 10| 2: [Identifier] b +# 10| 2: [Then] Then +# 10| 0: [ReservedWord] then +# 11| 1: [Identifier] c +# 12| 3: [ReservedWord] end +# 15| 7: [If] If +# 15| 0: [ReservedWord] if +# 15| 1: [Binary] Binary +# 15| 0: [Identifier] a +# 15| 1: [ReservedWord] == +# 15| 2: [Identifier] b +# 15| 2: [Then] Then +# 16| 0: [Identifier] c +# 17| 3: [Else] Else +# 17| 0: [ReservedWord] else +# 18| 1: [Identifier] d +# 19| 4: [ReservedWord] end +# 22| 8: [If] If +# 22| 0: [ReservedWord] if +# 22| 1: [Binary] Binary +# 22| 0: [Identifier] a +# 22| 1: [ReservedWord] == +# 22| 2: [Integer] 0 +# 22| 2: [Then] Then +# 22| 0: [ReservedWord] then +# 23| 1: [Identifier] c +# 24| 3: [Elsif] Elsif +# 24| 0: [ReservedWord] elsif +# 24| 1: [Binary] Binary +# 24| 0: [Identifier] a +# 24| 1: [ReservedWord] == +# 24| 2: [Integer] 1 +# 24| 2: [Then] Then +# 24| 0: [ReservedWord] then +# 25| 1: [Identifier] d +# 26| 3: [Elsif] Elsif +# 26| 0: [ReservedWord] elsif +# 26| 1: [Binary] Binary +# 26| 0: [Identifier] a +# 26| 1: [ReservedWord] == +# 26| 2: [Integer] 2 +# 26| 2: [Then] Then +# 26| 0: [ReservedWord] then +# 27| 1: [Identifier] e +# 28| 3: [Else] Else +# 28| 0: [ReservedWord] else +# 29| 1: [Identifier] f +# 30| 4: [ReservedWord] end +# 33| 9: [If] If +# 33| 0: [ReservedWord] if +# 33| 1: [Binary] Binary +# 33| 0: [Identifier] a +# 33| 1: [ReservedWord] == +# 33| 2: [Integer] 0 +# 33| 2: [Then] Then +# 34| 0: [Identifier] b +# 35| 3: [Elsif] Elsif +# 35| 0: [ReservedWord] elsif +# 35| 1: [Binary] Binary +# 35| 0: [Identifier] a +# 35| 1: [ReservedWord] == +# 35| 2: [Integer] 1 +# 35| 2: [Then] Then +# 36| 0: [Identifier] c +# 37| 4: [ReservedWord] end +# 40| 10: [Unless] Unless +# 40| 0: [ReservedWord] unless +# 40| 1: [Binary] Binary +# 40| 0: [Identifier] a +# 40| 1: [ReservedWord] > +# 40| 2: [Identifier] b +# 40| 2: [Then] Then +# 40| 0: [ReservedWord] then +# 41| 1: [Identifier] c +# 42| 3: [ReservedWord] end +# 45| 11: [Unless] Unless +# 45| 0: [ReservedWord] unless +# 45| 1: [Binary] Binary +# 45| 0: [Identifier] a +# 45| 1: [ReservedWord] == +# 45| 2: [Identifier] b +# 45| 2: [Then] Then +# 46| 0: [Identifier] c +# 47| 3: [Else] Else +# 47| 0: [ReservedWord] else +# 48| 1: [Identifier] d +# 49| 4: [ReservedWord] end +# 52| 12: [IfModifier] IfModifier +# 52| 0: [Assignment] Assignment +# 52| 0: [Identifier] a +# 52| 1: [ReservedWord] = +# 52| 2: [Identifier] b +# 52| 1: [ReservedWord] if +# 52| 2: [Binary] Binary +# 52| 0: [Identifier] c +# 52| 1: [ReservedWord] > +# 52| 2: [Identifier] d +# 55| 13: [UnlessModifier] UnlessModifier +# 55| 0: [Assignment] Assignment +# 55| 0: [Identifier] a +# 55| 1: [ReservedWord] = +# 55| 2: [Identifier] b +# 55| 1: [ReservedWord] unless +# 55| 2: [Binary] Binary +# 55| 0: [Identifier] c +# 55| 1: [ReservedWord] < +# 55| 2: [Identifier] d +# 58| 14: [Assignment] Assignment +# 58| 0: [Identifier] a +# 58| 1: [ReservedWord] = +# 58| 2: [Conditional] Conditional +# 58| 0: [Binary] Binary +# 58| 0: [Identifier] b +# 58| 1: [ReservedWord] > +# 58| 2: [Identifier] c +# 58| 1: [ReservedWord] ? +# 58| 2: [Binary] Binary +# 58| 0: [Identifier] d +# 58| 1: [ReservedWord] + +# 58| 2: [Integer] 1 +# 58| 3: [ReservedWord] : +# 58| 4: [Binary] Binary +# 58| 0: [Identifier] e +# 58| 1: [ReservedWord] - +# 58| 2: [Integer] 2 +# 61| 15: [If] If +# 61| 0: [ReservedWord] if +# 61| 1: [Binary] Binary +# 61| 0: [Identifier] a +# 61| 1: [ReservedWord] > +# 61| 2: [Identifier] b +# 61| 2: [Then] Then +# 61| 0: [ReservedWord] then +# 62| 1: [Identifier] c +# 63| 3: [Else] Else +# 63| 0: [ReservedWord] else +# 64| 4: [ReservedWord] end +# 67| 16: [If] If +# 67| 0: [ReservedWord] if +# 67| 1: [Binary] Binary +# 67| 0: [Identifier] a +# 67| 1: [ReservedWord] > +# 67| 2: [Identifier] b +# 67| 2: [Then] Then +# 67| 0: [ReservedWord] then +# 68| 3: [Else] Else +# 68| 0: [ReservedWord] else +# 69| 1: [Identifier] c +# 70| 4: [ReservedWord] end +# 1| [Comment] # Define some variables used below +# 9| [Comment] # If expr with no else +# 14| [Comment] # If expr with single else +# 21| [Comment] # If expr with multiple nested elsif branches +# 32| [Comment] # If expr with elsif and then no else +# 39| [Comment] # Unless expr with no else +# 44| [Comment] # Unless expr with else +# 51| [Comment] # If-modified expr +# 54| [Comment] # Unless-modified expr +# 57| [Comment] # Ternary if expr +# 60| [Comment] # If expr with empty else (treated as no else) +# 66| [Comment] # If expr with empty then (treated as no then) +control/loops.rb: +# 1| [Program] Program +# 2| 0: [Assignment] Assignment +# 2| 0: [Identifier] foo +# 2| 1: [ReservedWord] = +# 2| 2: [Integer] 0 +# 3| 1: [Assignment] Assignment +# 3| 0: [Identifier] sum +# 3| 1: [ReservedWord] = +# 3| 2: [Integer] 0 +# 4| 2: [Assignment] Assignment +# 4| 0: [Identifier] x +# 4| 1: [ReservedWord] = +# 4| 2: [Integer] 0 +# 5| 3: [Assignment] Assignment +# 5| 0: [Identifier] y +# 5| 1: [ReservedWord] = +# 5| 2: [Integer] 0 +# 6| 4: [Assignment] Assignment +# 6| 0: [Identifier] z +# 6| 1: [ReservedWord] = +# 6| 2: [Integer] 0 +# 9| 5: [For] For +# 9| 0: [ReservedWord] for +# 9| 1: [Identifier] n +# 9| 2: [In] In +# 9| 0: [ReservedWord] in +# 9| 1: [Range] Range +# 9| 0: [Integer] 1 +# 9| 1: [ReservedWord] .. +# 9| 2: [Integer] 10 +# 9| 3: [Do] Do +# 10| 0: [OperatorAssignment] OperatorAssignment +# 10| 0: [Identifier] sum +# 10| 1: [ReservedWord] += +# 10| 2: [Identifier] n +# 11| 1: [Assignment] Assignment +# 11| 0: [Identifier] foo +# 11| 1: [ReservedWord] = +# 11| 2: [Identifier] n +# 12| 2: [ReservedWord] end +# 16| 6: [For] For +# 16| 0: [ReservedWord] for +# 16| 1: [Identifier] n +# 16| 2: [In] In +# 16| 0: [ReservedWord] in +# 16| 1: [Range] Range +# 16| 0: [Integer] 1 +# 16| 1: [ReservedWord] .. +# 16| 2: [Integer] 10 +# 16| 3: [Do] Do +# 17| 0: [OperatorAssignment] OperatorAssignment +# 17| 0: [Identifier] sum +# 17| 1: [ReservedWord] += +# 17| 2: [Identifier] n +# 18| 1: [OperatorAssignment] OperatorAssignment +# 18| 0: [Identifier] foo +# 18| 1: [ReservedWord] -= +# 18| 2: [Identifier] n +# 19| 2: [ReservedWord] end +# 22| 7: [For] For +# 22| 0: [ReservedWord] for +# 22| 1: [LeftAssignmentList] LeftAssignmentList +# 22| 0: [Identifier] key +# 22| 1: [ReservedWord] , +# 22| 2: [Identifier] value +# 22| 2: [In] In +# 22| 0: [ReservedWord] in +# 22| 1: [Hash] Hash +# 22| 0: [ReservedWord] { +# 22| 1: [Pair] Pair +# 22| 0: [HashKeySymbol] foo +# 22| 1: [ReservedWord] : +# 22| 2: [Integer] 0 +# 22| 2: [ReservedWord] , +# 22| 3: [Pair] Pair +# 22| 0: [HashKeySymbol] bar +# 22| 1: [ReservedWord] : +# 22| 2: [Integer] 1 +# 22| 4: [ReservedWord] } +# 22| 3: [Do] Do +# 23| 0: [OperatorAssignment] OperatorAssignment +# 23| 0: [Identifier] sum +# 23| 1: [ReservedWord] += +# 23| 2: [Identifier] value +# 24| 1: [OperatorAssignment] OperatorAssignment +# 24| 0: [Identifier] foo +# 24| 1: [ReservedWord] *= +# 24| 2: [Identifier] value +# 25| 2: [ReservedWord] end +# 28| 8: [For] For +# 28| 0: [ReservedWord] for +# 28| 1: [LeftAssignmentList] LeftAssignmentList +# 28| 0: [DestructuredLeftAssignment] DestructuredLeftAssignment +# 28| 0: [ReservedWord] ( +# 28| 1: [Identifier] key +# 28| 2: [ReservedWord] , +# 28| 3: [Identifier] value +# 28| 4: [ReservedWord] ) +# 28| 2: [In] In +# 28| 0: [ReservedWord] in +# 28| 1: [Hash] Hash +# 28| 0: [ReservedWord] { +# 28| 1: [Pair] Pair +# 28| 0: [HashKeySymbol] foo +# 28| 1: [ReservedWord] : +# 28| 2: [Integer] 0 +# 28| 2: [ReservedWord] , +# 28| 3: [Pair] Pair +# 28| 0: [HashKeySymbol] bar +# 28| 1: [ReservedWord] : +# 28| 2: [Integer] 1 +# 28| 4: [ReservedWord] } +# 28| 3: [Do] Do +# 29| 0: [OperatorAssignment] OperatorAssignment +# 29| 0: [Identifier] sum +# 29| 1: [ReservedWord] += +# 29| 2: [Identifier] value +# 30| 1: [OperatorAssignment] OperatorAssignment +# 30| 0: [Identifier] foo +# 30| 1: [ReservedWord] /= +# 30| 2: [Identifier] value +# 31| 2: [Break] Break +# 31| 0: [ReservedWord] break +# 32| 3: [ReservedWord] end +# 35| 9: [While] While +# 35| 0: [ReservedWord] while +# 35| 1: [Binary] Binary +# 35| 0: [Identifier] x +# 35| 1: [ReservedWord] < +# 35| 2: [Identifier] y +# 35| 2: [Do] Do +# 36| 0: [OperatorAssignment] OperatorAssignment +# 36| 0: [Identifier] x +# 36| 1: [ReservedWord] += +# 36| 2: [Integer] 1 +# 37| 1: [OperatorAssignment] OperatorAssignment +# 37| 0: [Identifier] z +# 37| 1: [ReservedWord] += +# 37| 2: [Integer] 1 +# 38| 2: [Next] Next +# 38| 0: [ReservedWord] next +# 39| 3: [ReservedWord] end +# 42| 10: [While] While +# 42| 0: [ReservedWord] while +# 42| 1: [Binary] Binary +# 42| 0: [Identifier] x +# 42| 1: [ReservedWord] < +# 42| 2: [Identifier] y +# 42| 2: [Do] Do +# 42| 0: [ReservedWord] do +# 43| 1: [OperatorAssignment] OperatorAssignment +# 43| 0: [Identifier] x +# 43| 1: [ReservedWord] += +# 43| 2: [Integer] 1 +# 44| 2: [OperatorAssignment] OperatorAssignment +# 44| 0: [Identifier] z +# 44| 1: [ReservedWord] += +# 44| 2: [Integer] 2 +# 45| 3: [ReservedWord] end +# 48| 11: [WhileModifier] WhileModifier +# 48| 0: [OperatorAssignment] OperatorAssignment +# 48| 0: [Identifier] x +# 48| 1: [ReservedWord] += +# 48| 2: [Integer] 1 +# 48| 1: [ReservedWord] while +# 48| 2: [Binary] Binary +# 48| 0: [Identifier] y +# 48| 1: [ReservedWord] >= +# 48| 2: [Identifier] x +# 51| 12: [Until] Until +# 51| 0: [ReservedWord] until +# 51| 1: [Binary] Binary +# 51| 0: [Identifier] x +# 51| 1: [ReservedWord] == +# 51| 2: [Identifier] y +# 51| 2: [Do] Do +# 52| 0: [OperatorAssignment] OperatorAssignment +# 52| 0: [Identifier] x +# 52| 1: [ReservedWord] += +# 52| 2: [Integer] 1 +# 53| 1: [OperatorAssignment] OperatorAssignment +# 53| 0: [Identifier] z +# 53| 1: [ReservedWord] -= +# 53| 2: [Integer] 1 +# 54| 2: [ReservedWord] end +# 57| 13: [Until] Until +# 57| 0: [ReservedWord] until +# 57| 1: [Binary] Binary +# 57| 0: [Identifier] x +# 57| 1: [ReservedWord] > +# 57| 2: [Identifier] y +# 57| 2: [Do] Do +# 57| 0: [ReservedWord] do +# 58| 1: [OperatorAssignment] OperatorAssignment +# 58| 0: [Identifier] x +# 58| 1: [ReservedWord] += +# 58| 2: [Integer] 1 +# 59| 2: [OperatorAssignment] OperatorAssignment +# 59| 0: [Identifier] z +# 59| 1: [ReservedWord] -= +# 59| 2: [Integer] 4 +# 60| 3: [ReservedWord] end +# 63| 14: [UntilModifier] UntilModifier +# 63| 0: [OperatorAssignment] OperatorAssignment +# 63| 0: [Identifier] x +# 63| 1: [ReservedWord] -= +# 63| 2: [Integer] 1 +# 63| 1: [ReservedWord] until +# 63| 2: [Binary] Binary +# 63| 0: [Identifier] x +# 63| 1: [ReservedWord] == +# 63| 2: [Integer] 0 +# 66| 15: [While] While +# 66| 0: [ReservedWord] while +# 66| 1: [Binary] Binary +# 66| 0: [Identifier] x +# 66| 1: [ReservedWord] < +# 66| 2: [Identifier] y +# 66| 2: [Do] Do +# 66| 0: [ReservedWord] do +# 67| 1: [ReservedWord] end +# 1| [Comment] # Define some variables used below. +# 8| [Comment] # For loop with a single variable as the iteration argument +# 14| [Comment] # For loop with a single variable and a trailing comma as the iteration +# 15| [Comment] # argument +# 21| [Comment] # For loop with a tuple pattern as the iteration argument +# 27| [Comment] # Same, but with parentheses around the pattern +# 34| [Comment] # While loop +# 41| [Comment] # While loop with `do` keyword +# 47| [Comment] # While-modified expression +# 50| [Comment] # Until loop +# 56| [Comment] # Until loop with `do` keyword +# 62| [Comment] # Until-modified expression +# 65| [Comment] # While loop with empty `do` block +erb/template.html.erb: +# 19| [Program] Program +# 19| 0: [String] String +# 19| 0: [ReservedWord] " +# 19| 1: [StringContent] hello world +# 19| 2: [ReservedWord] " +# 25| 1: [Assignment] Assignment +# 25| 0: [Identifier] xs +# 25| 1: [ReservedWord] = +# 25| 2: [String] String +# 25| 0: [ReservedWord] " +# 25| 1: [ReservedWord] " +# 27| 2: [For] For +# 27| 0: [ReservedWord] for +# 27| 1: [Identifier] x +# 27| 2: [In] In +# 27| 0: [ReservedWord] in +# 27| 1: [Array] Array +# 27| 0: [ReservedWord] [ +# 27| 1: [String] String +# 27| 0: [ReservedWord] " +# 27| 1: [StringContent] foo +# 27| 2: [ReservedWord] " +# 27| 2: [ReservedWord] , +# 27| 3: [String] String +# 27| 0: [ReservedWord] " +# 27| 1: [StringContent] bar +# 27| 2: [ReservedWord] " +# 27| 4: [ReservedWord] , +# 27| 5: [String] String +# 27| 0: [ReservedWord] " +# 27| 1: [StringContent] baz +# 27| 2: [ReservedWord] " +# 27| 6: [ReservedWord] ] +# 27| 3: [Do] Do +# 27| 0: [ReservedWord] do +# 28| 1: [OperatorAssignment] OperatorAssignment +# 28| 0: [Identifier] xs +# 28| 1: [ReservedWord] += +# 28| 2: [Identifier] x +# 29| 2: [Identifier] xs +# 31| 3: [ReservedWord] end +escape_sequences/escapes.rb: +# 1| [Program] Program +# 6| 0: [String] String +# 6| 0: [ReservedWord] ' +# 6| 1: [StringContent] \' +# 6| 2: [ReservedWord] ' +# 7| 1: [String] String +# 7| 0: [ReservedWord] ' +# 7| 1: [StringContent] \" +# 7| 2: [ReservedWord] ' +# 8| 2: [String] String +# 8| 0: [ReservedWord] ' +# 8| 1: [StringContent] \\ +# 8| 2: [ReservedWord] ' +# 9| 3: [String] String +# 9| 0: [ReservedWord] ' +# 9| 1: [StringContent] \1 +# 9| 2: [ReservedWord] ' +# 10| 4: [String] String +# 10| 0: [ReservedWord] ' +# 10| 1: [StringContent] \\1 +# 10| 2: [ReservedWord] ' +# 11| 5: [String] String +# 11| 0: [ReservedWord] ' +# 11| 1: [StringContent] \141 +# 11| 2: [ReservedWord] ' +# 12| 6: [String] String +# 12| 0: [ReservedWord] ' +# 12| 1: [StringContent] \n +# 12| 2: [ReservedWord] ' +# 15| 7: [String] String +# 15| 0: [ReservedWord] " +# 15| 1: [EscapeSequence] \' +# 15| 2: [ReservedWord] " +# 16| 8: [String] String +# 16| 0: [ReservedWord] " +# 16| 1: [EscapeSequence] \" +# 16| 2: [ReservedWord] " +# 17| 9: [String] String +# 17| 0: [ReservedWord] " +# 17| 1: [EscapeSequence] \\ +# 17| 2: [ReservedWord] " +# 18| 10: [String] String +# 18| 0: [ReservedWord] " +# 18| 1: [EscapeSequence] \1 +# 18| 2: [ReservedWord] " +# 19| 11: [String] String +# 19| 0: [ReservedWord] " +# 19| 1: [EscapeSequence] \\ +# 19| 2: [StringContent] 1 +# 19| 3: [ReservedWord] " +# 20| 12: [String] String +# 20| 0: [ReservedWord] " +# 20| 1: [EscapeSequence] \141 +# 20| 2: [ReservedWord] " +# 21| 13: [String] String +# 21| 0: [ReservedWord] " +# 21| 1: [EscapeSequence] \x6d +# 21| 2: [ReservedWord] " +# 22| 14: [String] String +# 22| 0: [ReservedWord] " +# 22| 1: [EscapeSequence] \x6E +# 22| 2: [ReservedWord] " +# 23| 15: [String] String +# 23| 0: [ReservedWord] " +# 23| 1: [EscapeSequence] \X +# 23| 2: [StringContent] 6d +# 23| 3: [ReservedWord] " +# 24| 16: [String] String +# 24| 0: [ReservedWord] " +# 24| 1: [EscapeSequence] \X +# 24| 2: [StringContent] 6E +# 24| 3: [ReservedWord] " +# 25| 17: [String] String +# 25| 0: [ReservedWord] " +# 25| 1: [EscapeSequence] \u203d +# 25| 2: [ReservedWord] " +# 26| 18: [String] String +# 26| 0: [ReservedWord] " +# 26| 1: [EscapeSequence] \u{62} +# 26| 2: [ReservedWord] " +# 27| 19: [String] String +# 27| 0: [ReservedWord] " +# 27| 1: [EscapeSequence] \u{1f60a} +# 27| 2: [ReservedWord] " +# 28| 20: [String] String +# 28| 0: [ReservedWord] " +# 28| 1: [EscapeSequence] \a +# 28| 2: [ReservedWord] " +# 29| 21: [String] String +# 29| 0: [ReservedWord] " +# 29| 1: [EscapeSequence] \b +# 29| 2: [ReservedWord] " +# 30| 22: [String] String +# 30| 0: [ReservedWord] " +# 30| 1: [EscapeSequence] \t +# 30| 2: [ReservedWord] " +# 31| 23: [String] String +# 31| 0: [ReservedWord] " +# 31| 1: [EscapeSequence] \n +# 31| 2: [ReservedWord] " +# 32| 24: [String] String +# 32| 0: [ReservedWord] " +# 32| 1: [EscapeSequence] \v +# 32| 2: [ReservedWord] " +# 33| 25: [String] String +# 33| 0: [ReservedWord] " +# 33| 1: [EscapeSequence] \f +# 33| 2: [ReservedWord] " +# 34| 26: [String] String +# 34| 0: [ReservedWord] " +# 34| 1: [EscapeSequence] \r +# 34| 2: [ReservedWord] " +# 35| 27: [String] String +# 35| 0: [ReservedWord] " +# 35| 1: [EscapeSequence] \e +# 35| 2: [ReservedWord] " +# 36| 28: [String] String +# 36| 0: [ReservedWord] " +# 36| 1: [EscapeSequence] \s +# 36| 2: [ReservedWord] " +# 37| 29: [String] String +# 37| 0: [ReservedWord] " +# 37| 1: [EscapeSequence] \c +# 37| 2: [StringContent] ? +# 37| 3: [ReservedWord] " +# 38| 30: [String] String +# 38| 0: [ReservedWord] " +# 38| 1: [EscapeSequence] \C +# 38| 2: [StringContent] -? +# 38| 3: [ReservedWord] " +# 43| 31: [Assignment] Assignment +# 43| 0: [Identifier] a +# 43| 1: [ReservedWord] = +# 43| 2: [String] String +# 43| 0: [ReservedWord] " +# 43| 1: [EscapeSequence] \\ +# 43| 2: [StringContent] . +# 43| 3: [ReservedWord] " +# 44| 32: [String] String +# 44| 0: [ReservedWord] " +# 44| 1: [Interpolation] Interpolation +# 44| 0: [ReservedWord] #{ +# 44| 1: [Identifier] a +# 44| 2: [ReservedWord] } +# 44| 2: [ReservedWord] " +# 48| 33: [Regex] Regex +# 48| 0: [ReservedWord] / +# 48| 1: [EscapeSequence] \n +# 48| 2: [ReservedWord] / +# 49| 34: [Regex] Regex +# 49| 0: [ReservedWord] / +# 49| 1: [EscapeSequence] \p +# 49| 2: [ReservedWord] / +# 50| 35: [Regex] Regex +# 50| 0: [ReservedWord] / +# 50| 1: [EscapeSequence] \u0061 +# 50| 2: [ReservedWord] / +# 53| 36: [Assignment] Assignment +# 53| 0: [Identifier] a +# 53| 1: [ReservedWord] = +# 53| 2: [String] String +# 53| 0: [ReservedWord] " +# 53| 1: [EscapeSequence] \\ +# 53| 2: [StringContent] . +# 53| 3: [ReservedWord] " +# 54| 37: [Assignment] Assignment +# 54| 0: [Identifier] b +# 54| 1: [ReservedWord] = +# 54| 2: [Regex] Regex +# 54| 0: [ReservedWord] / +# 54| 1: [EscapeSequence] \. +# 54| 2: [ReservedWord] / +# 55| 38: [Regex] Regex +# 55| 0: [ReservedWord] / +# 55| 1: [Interpolation] Interpolation +# 55| 0: [ReservedWord] #{ +# 55| 1: [Identifier] a +# 55| 2: [ReservedWord] } +# 55| 2: [Interpolation] Interpolation +# 55| 0: [ReservedWord] #{ +# 55| 1: [Identifier] b +# 55| 2: [ReservedWord] } +# 55| 3: [ReservedWord] / +# 58| 39: [StringArray] StringArray +# 58| 0: [ReservedWord] %w[ +# 58| 1: [BareString] BareString +# 58| 0: [StringContent] foo +# 58| 1: [EscapeSequence] \n +# 58| 2: [BareString] BareString +# 58| 0: [StringContent] bar +# 58| 3: [ReservedWord] ] +# 61| 40: [DelimitedSymbol] DelimitedSymbol +# 61| 0: [ReservedWord] :' +# 61| 1: [StringContent] \' +# 61| 2: [ReservedWord] ' +# 62| 41: [DelimitedSymbol] DelimitedSymbol +# 62| 0: [ReservedWord] :' +# 62| 1: [StringContent] \" +# 62| 2: [ReservedWord] ' +# 63| 42: [DelimitedSymbol] DelimitedSymbol +# 63| 0: [ReservedWord] :' +# 63| 1: [StringContent] \\ +# 63| 2: [ReservedWord] ' +# 64| 43: [DelimitedSymbol] DelimitedSymbol +# 64| 0: [ReservedWord] :' +# 64| 1: [StringContent] \1 +# 64| 2: [ReservedWord] ' +# 65| 44: [DelimitedSymbol] DelimitedSymbol +# 65| 0: [ReservedWord] :' +# 65| 1: [StringContent] \\1 +# 65| 2: [ReservedWord] ' +# 66| 45: [DelimitedSymbol] DelimitedSymbol +# 66| 0: [ReservedWord] :' +# 66| 1: [StringContent] \141 +# 66| 2: [ReservedWord] ' +# 67| 46: [DelimitedSymbol] DelimitedSymbol +# 67| 0: [ReservedWord] :' +# 67| 1: [StringContent] \n +# 67| 2: [ReservedWord] ' +# 70| 47: [DelimitedSymbol] DelimitedSymbol +# 70| 0: [ReservedWord] :" +# 70| 1: [EscapeSequence] \' +# 70| 2: [ReservedWord] " +# 71| 48: [DelimitedSymbol] DelimitedSymbol +# 71| 0: [ReservedWord] :" +# 71| 1: [EscapeSequence] \" +# 71| 2: [ReservedWord] " +# 72| 49: [DelimitedSymbol] DelimitedSymbol +# 72| 0: [ReservedWord] :" +# 72| 1: [EscapeSequence] \\ +# 72| 2: [ReservedWord] " +# 73| 50: [DelimitedSymbol] DelimitedSymbol +# 73| 0: [ReservedWord] :" +# 73| 1: [EscapeSequence] \1 +# 73| 2: [ReservedWord] " +# 74| 51: [DelimitedSymbol] DelimitedSymbol +# 74| 0: [ReservedWord] :" +# 74| 1: [EscapeSequence] \\ +# 74| 2: [StringContent] 1 +# 74| 3: [ReservedWord] " +# 75| 52: [DelimitedSymbol] DelimitedSymbol +# 75| 0: [ReservedWord] :" +# 75| 1: [EscapeSequence] \141 +# 75| 2: [ReservedWord] " +# 76| 53: [DelimitedSymbol] DelimitedSymbol +# 76| 0: [ReservedWord] :" +# 76| 1: [EscapeSequence] \x6d +# 76| 2: [ReservedWord] " +# 77| 54: [DelimitedSymbol] DelimitedSymbol +# 77| 0: [ReservedWord] :" +# 77| 1: [EscapeSequence] \x6E +# 77| 2: [ReservedWord] " +# 78| 55: [DelimitedSymbol] DelimitedSymbol +# 78| 0: [ReservedWord] :" +# 78| 1: [EscapeSequence] \X +# 78| 2: [StringContent] 6d +# 78| 3: [ReservedWord] " +# 79| 56: [DelimitedSymbol] DelimitedSymbol +# 79| 0: [ReservedWord] :" +# 79| 1: [EscapeSequence] \X +# 79| 2: [StringContent] 6E +# 79| 3: [ReservedWord] " +# 80| 57: [DelimitedSymbol] DelimitedSymbol +# 80| 0: [ReservedWord] :" +# 80| 1: [EscapeSequence] \u203d +# 80| 2: [ReservedWord] " +# 81| 58: [DelimitedSymbol] DelimitedSymbol +# 81| 0: [ReservedWord] :" +# 81| 1: [EscapeSequence] \u{62} +# 81| 2: [ReservedWord] " +# 82| 59: [DelimitedSymbol] DelimitedSymbol +# 82| 0: [ReservedWord] :" +# 82| 1: [EscapeSequence] \u{1f60a} +# 82| 2: [ReservedWord] " +# 83| 60: [DelimitedSymbol] DelimitedSymbol +# 83| 0: [ReservedWord] :" +# 83| 1: [EscapeSequence] \a +# 83| 2: [ReservedWord] " +# 84| 61: [DelimitedSymbol] DelimitedSymbol +# 84| 0: [ReservedWord] :" +# 84| 1: [EscapeSequence] \b +# 84| 2: [ReservedWord] " +# 85| 62: [DelimitedSymbol] DelimitedSymbol +# 85| 0: [ReservedWord] :" +# 85| 1: [EscapeSequence] \t +# 85| 2: [ReservedWord] " +# 86| 63: [DelimitedSymbol] DelimitedSymbol +# 86| 0: [ReservedWord] :" +# 86| 1: [EscapeSequence] \n +# 86| 2: [ReservedWord] " +# 87| 64: [DelimitedSymbol] DelimitedSymbol +# 87| 0: [ReservedWord] :" +# 87| 1: [EscapeSequence] \v +# 87| 2: [ReservedWord] " +# 88| 65: [DelimitedSymbol] DelimitedSymbol +# 88| 0: [ReservedWord] :" +# 88| 1: [EscapeSequence] \f +# 88| 2: [ReservedWord] " +# 89| 66: [DelimitedSymbol] DelimitedSymbol +# 89| 0: [ReservedWord] :" +# 89| 1: [EscapeSequence] \r +# 89| 2: [ReservedWord] " +# 90| 67: [DelimitedSymbol] DelimitedSymbol +# 90| 0: [ReservedWord] :" +# 90| 1: [EscapeSequence] \e +# 90| 2: [ReservedWord] " +# 91| 68: [DelimitedSymbol] DelimitedSymbol +# 91| 0: [ReservedWord] :" +# 91| 1: [EscapeSequence] \s +# 91| 2: [ReservedWord] " +# 92| 69: [DelimitedSymbol] DelimitedSymbol +# 92| 0: [ReservedWord] :" +# 92| 1: [EscapeSequence] \c +# 92| 2: [StringContent] ? +# 92| 3: [ReservedWord] " +# 93| 70: [DelimitedSymbol] DelimitedSymbol +# 93| 0: [ReservedWord] :" +# 93| 1: [EscapeSequence] \C +# 93| 2: [StringContent] -? +# 93| 3: [ReservedWord] " +# 1| [Comment] # Most comments indicate the contents of the string after MRI has parsed the +# 2| [Comment] # escape sequences (i.e. what gets printed by `puts`), and that's what we expect +# 3| [Comment] # `getConstantValue().getString()` to return. +# 5| [Comment] # The only escapes in single-quoted strings are backslash and single-quote. +# 6| [Comment] # ' +# 7| [Comment] # \" +# 8| [Comment] # \ +# 9| [Comment] # \1 +# 10| [Comment] # \1 +# 11| [Comment] # \141 +# 12| [Comment] # \n +# 14| [Comment] # Double-quoted strings +# 15| [Comment] # ' +# 16| [Comment] # " +# 17| [Comment] # \ +# 18| [Comment] # +# 19| [Comment] # \1 +# 20| [Comment] # a +# 21| [Comment] # m +# 22| [Comment] # n +# 23| [Comment] # X6d +# 24| [Comment] # X6E +# 25| [Comment] # ‽ +# 26| [Comment] # b +# 27| [Comment] # 😊 +# 28| [Comment] # +# 29| [Comment] # +# 30| [Comment] # +# 31| [Comment] # +# 32| [Comment] # +# 33| [Comment] #
    +# 34| [Comment] # +# 35| [Comment] # +# 36| [Comment] # +# 37| [Comment] # problem: only \c is parsed as part of the escape sequence +# 38| [Comment] # problem: only \C is parsed as part of the escape sequence +# 40| [Comment] # TODO: support/test more control characters: \M-..., \cx, \C-x, etc. +# 42| [Comment] # String interpolation +# 43| [Comment] # \. +# 44| [Comment] # \. +# 46| [Comment] # Regexps - escape sequences are handled by the regex parser, so their constant +# 47| [Comment] # value should be interpreted literally and not unescaped as in double-quoted strings +# 52| [Comment] # Regexp interpolation +# 53| [Comment] # \. +# 55| [Comment] # equivalent to /\.\./ +# 57| [Comment] # String arrays +# 58| [Comment] # should be equivalent to ["foo", "\\n", "bar"], but currently misparsed as ["foo \\n", "bar"] +# 60| [Comment] # Single-quoted symbols. Comments indicate the expected, unescaped string contents. +# 61| [Comment] # ' +# 62| [Comment] # \" +# 63| [Comment] # \ +# 64| [Comment] # \1 +# 65| [Comment] # \1 +# 66| [Comment] # \141 +# 67| [Comment] # \n +# 69| [Comment] # Double-quoted symbols. Comments indicate the expected, unescaped string contents. +# 70| [Comment] # ' +# 71| [Comment] # " +# 72| [Comment] # \ +# 73| [Comment] # +# 74| [Comment] # \1 +# 75| [Comment] # a +# 76| [Comment] # m +# 77| [Comment] # n +# 78| [Comment] # X6d +# 79| [Comment] # X6E +# 80| [Comment] # ‽ +# 81| [Comment] # b +# 82| [Comment] # 😊 +# 83| [Comment] # +# 84| [Comment] # +# 85| [Comment] # +# 86| [Comment] # +# 87| [Comment] # +# 88| [Comment] # +# 89| [Comment] # +# 90| [Comment] # +# 91| [Comment] # +# 92| [Comment] # problem: only \c is parsed as part of the escape sequence +# 93| [Comment] # problem: only \C is parsed as part of the escape sequence +gems/Gemfile: +# 1| [Program] Program +# 1| 0: [Call] Call +# 1| 0: [Identifier] source +# 1| 1: [ArgumentList] ArgumentList +# 1| 0: [String] String +# 1| 0: [ReservedWord] ' +# 1| 1: [StringContent] https://rubygems.org +# 1| 2: [ReservedWord] ' +# 3| 1: [Call] Call +# 3| 0: [Identifier] gem +# 3| 1: [ArgumentList] ArgumentList +# 3| 0: [String] String +# 3| 0: [ReservedWord] ' +# 3| 1: [StringContent] foo_gem +# 3| 2: [ReservedWord] ' +# 3| 1: [ReservedWord] , +# 3| 2: [String] String +# 3| 0: [ReservedWord] ' +# 3| 1: [StringContent] ~> 2.0 +# 3| 2: [ReservedWord] ' +# 5| 2: [Call] Call +# 5| 0: [Identifier] source +# 5| 1: [ArgumentList] ArgumentList +# 5| 0: [String] String +# 5| 0: [ReservedWord] ' +# 5| 1: [StringContent] https://gems.example.com +# 5| 2: [ReservedWord] ' +# 5| 2: [DoBlock] DoBlock +# 5| 0: [ReservedWord] do +# 6| 1: [Call] Call +# 6| 0: [Identifier] gem +# 6| 1: [ArgumentList] ArgumentList +# 6| 0: [String] String +# 6| 0: [ReservedWord] ' +# 6| 1: [StringContent] my_gem +# 6| 2: [ReservedWord] ' +# 6| 1: [ReservedWord] , +# 6| 2: [String] String +# 6| 0: [ReservedWord] ' +# 6| 1: [StringContent] 1.0 +# 6| 2: [ReservedWord] ' +# 7| 2: [Call] Call +# 7| 0: [Identifier] gem +# 7| 1: [ArgumentList] ArgumentList +# 7| 0: [String] String +# 7| 0: [ReservedWord] ' +# 7| 1: [StringContent] another_gem +# 7| 2: [ReservedWord] ' +# 7| 1: [ReservedWord] , +# 7| 2: [String] String +# 7| 0: [ReservedWord] ' +# 7| 1: [StringContent] 3.1.4 +# 7| 2: [ReservedWord] ' +# 8| 3: [ReservedWord] end +gems/lib/test.rb: +# 1| [Program] Program +# 1| 0: [Class] Class +# 1| 0: [ReservedWord] class +# 1| 1: [Constant] Foo +# 2| 2: [SingletonMethod] SingletonMethod +# 2| 0: [ReservedWord] def +# 2| 1: [Self] self +# 2| 2: [ReservedWord] . +# 2| 3: [Identifier] greet +# 3| 4: [Call] Call +# 3| 0: [Identifier] puts +# 3| 1: [ArgumentList] ArgumentList +# 3| 0: [String] String +# 3| 0: [ReservedWord] " +# 3| 1: [StringContent] Hello +# 3| 2: [ReservedWord] " +# 4| 5: [ReservedWord] end +# 5| 3: [ReservedWord] end +gems/test.gemspec: +# 1| [Program] Program +# 1| 0: [Call] Call +# 1| 0: [ScopeResolution] ScopeResolution +# 1| 0: [Constant] Gem +# 1| 1: [ReservedWord] :: +# 1| 2: [Constant] Specification +# 1| 1: [ReservedWord] . +# 1| 2: [Identifier] new +# 1| 3: [DoBlock] DoBlock +# 1| 0: [ReservedWord] do +# 1| 1: [BlockParameters] BlockParameters +# 1| 0: [ReservedWord] | +# 1| 1: [Identifier] s +# 1| 2: [ReservedWord] | +# 2| 2: [Assignment] Assignment +# 2| 0: [Call] Call +# 2| 0: [Identifier] s +# 2| 1: [ReservedWord] . +# 2| 2: [Identifier] name +# 2| 1: [ReservedWord] = +# 2| 2: [String] String +# 2| 0: [ReservedWord] ' +# 2| 1: [StringContent] test +# 2| 2: [ReservedWord] ' +# 3| 3: [Assignment] Assignment +# 3| 0: [Call] Call +# 3| 0: [Identifier] s +# 3| 1: [ReservedWord] . +# 3| 2: [Identifier] version +# 3| 1: [ReservedWord] = +# 3| 2: [String] String +# 3| 0: [ReservedWord] ' +# 3| 1: [StringContent] 0.0.0 +# 3| 2: [ReservedWord] ' +# 4| 4: [Assignment] Assignment +# 4| 0: [Call] Call +# 4| 0: [Identifier] s +# 4| 1: [ReservedWord] . +# 4| 2: [Identifier] summary +# 4| 1: [ReservedWord] = +# 4| 2: [String] String +# 4| 0: [ReservedWord] " +# 4| 1: [StringContent] foo! +# 4| 2: [ReservedWord] " +# 5| 5: [Assignment] Assignment +# 5| 0: [Call] Call +# 5| 0: [Identifier] s +# 5| 1: [ReservedWord] . +# 5| 2: [Identifier] description +# 5| 1: [ReservedWord] = +# 5| 2: [String] String +# 5| 0: [ReservedWord] " +# 5| 1: [StringContent] A test +# 5| 2: [ReservedWord] " +# 6| 6: [Assignment] Assignment +# 6| 0: [Call] Call +# 6| 0: [Identifier] s +# 6| 1: [ReservedWord] . +# 6| 2: [Identifier] authors +# 6| 1: [ReservedWord] = +# 6| 2: [Array] Array +# 6| 0: [ReservedWord] [ +# 6| 1: [String] String +# 6| 0: [ReservedWord] " +# 6| 1: [StringContent] Mona Lisa +# 6| 2: [ReservedWord] " +# 6| 2: [ReservedWord] ] +# 7| 7: [Assignment] Assignment +# 7| 0: [Call] Call +# 7| 0: [Identifier] s +# 7| 1: [ReservedWord] . +# 7| 2: [Identifier] email +# 7| 1: [ReservedWord] = +# 7| 2: [String] String +# 7| 0: [ReservedWord] ' +# 7| 1: [StringContent] mona@example.com +# 7| 2: [ReservedWord] ' +# 8| 8: [Assignment] Assignment +# 8| 0: [Call] Call +# 8| 0: [Identifier] s +# 8| 1: [ReservedWord] . +# 8| 2: [Identifier] files +# 8| 1: [ReservedWord] = +# 8| 2: [Array] Array +# 8| 0: [ReservedWord] [ +# 8| 1: [String] String +# 8| 0: [ReservedWord] " +# 8| 1: [StringContent] lib/test.rb +# 8| 2: [ReservedWord] " +# 8| 2: [ReservedWord] ] +# 9| 9: [Assignment] Assignment +# 9| 0: [Call] Call +# 9| 0: [Identifier] s +# 9| 1: [ReservedWord] . +# 9| 2: [Identifier] homepage +# 9| 1: [ReservedWord] = +# 9| 2: [String] String +# 9| 0: [ReservedWord] ' +# 9| 1: [StringContent] https://github.com/github/codeql-ruby +# 9| 2: [ReservedWord] ' +# 10| 10: [ReservedWord] end +literals/literals.rb: +# 1| [Program] Program +# 2| 0: [Nil] nil +# 3| 1: [Nil] NIL +# 4| 2: [False] false +# 5| 3: [False] FALSE +# 6| 4: [True] true +# 7| 5: [True] TRUE +# 10| 6: [Integer] 1234 +# 11| 7: [Integer] 5_678 +# 12| 8: [Integer] 0 +# 13| 9: [Integer] 0d900 +# 14| 10: [Integer] 2147483647 +# 15| 11: [Integer] 2147483648 +# 18| 12: [Integer] 0x1234 +# 19| 13: [Integer] 0xbeef +# 20| 14: [Integer] 0xF0_0D +# 21| 15: [Integer] 0x000000000000000000ff +# 22| 16: [Integer] 0x7FFF_FFFF +# 23| 17: [Integer] 0x80000000 +# 24| 18: [Integer] 0xdeadbeef +# 25| 19: [Integer] 0xF00D_face +# 28| 20: [Integer] 0123 +# 29| 21: [Integer] 0o234 +# 30| 22: [Integer] 0O45_6 +# 31| 23: [Integer] 0000000000000000000000000000010 +# 32| 24: [Integer] 017777777777 +# 33| 25: [Integer] 020000000000 +# 36| 26: [Integer] 0b10010100 +# 37| 27: [Integer] 0B011_01101 +# 38| 28: [Integer] 0b00000000000000000000000000000000000000011 +# 39| 29: [Integer] 0b01111111111111111111111111111111 +# 40| 30: [Integer] 0b10000000000000000000000000000000 +# 43| 31: [Float] 12.34 +# 44| 32: [Float] 1234e-2 +# 45| 33: [Float] 1.234E1 +# 48| 34: [Rational] Rational +# 48| 0: [Integer] 23 +# 48| 1: [ReservedWord] r +# 49| 35: [Rational] Rational +# 49| 0: [Float] 9.85 +# 49| 1: [ReservedWord] r +# 52| 36: [Complex] 2i +# 59| 37: [String] String +# 59| 0: [ReservedWord] " +# 59| 1: [ReservedWord] " +# 60| 38: [String] String +# 60| 0: [ReservedWord] ' +# 60| 1: [ReservedWord] ' +# 61| 39: [String] String +# 61| 0: [ReservedWord] " +# 61| 1: [StringContent] hello +# 61| 2: [ReservedWord] " +# 62| 40: [String] String +# 62| 0: [ReservedWord] ' +# 62| 1: [StringContent] goodbye +# 62| 2: [ReservedWord] ' +# 63| 41: [String] String +# 63| 0: [ReservedWord] " +# 63| 1: [StringContent] string with escaped +# 63| 2: [EscapeSequence] \" +# 63| 3: [StringContent] quote +# 63| 4: [ReservedWord] " +# 64| 42: [String] String +# 64| 0: [ReservedWord] ' +# 64| 1: [StringContent] string with " quote +# 64| 2: [ReservedWord] ' +# 65| 43: [String] String +# 65| 0: [ReservedWord] %( +# 65| 1: [StringContent] foo bar baz +# 65| 2: [ReservedWord] ) +# 66| 44: [String] String +# 66| 0: [ReservedWord] %q< +# 66| 1: [StringContent] foo bar baz +# 66| 2: [ReservedWord] > +# 67| 45: [String] String +# 67| 0: [ReservedWord] %q( +# 67| 1: [StringContent] foo ' bar " baz' +# 67| 2: [ReservedWord] ) +# 68| 46: [String] String +# 68| 0: [ReservedWord] %Q( +# 68| 1: [StringContent] FOO ' BAR " BAZ' +# 68| 2: [ReservedWord] ) +# 69| 47: [String] String +# 69| 0: [ReservedWord] %q( +# 69| 1: [StringContent] foo\ bar +# 69| 2: [ReservedWord] ) +# 70| 48: [String] String +# 70| 0: [ReservedWord] %Q( +# 70| 1: [StringContent] foo +# 70| 2: [EscapeSequence] \ +# 70| 3: [StringContent] bar +# 70| 4: [ReservedWord] ) +# 71| 49: [String] String +# 71| 0: [ReservedWord] " +# 71| 1: [StringContent] 2 + 2 = +# 71| 2: [Interpolation] Interpolation +# 71| 0: [ReservedWord] #{ +# 71| 1: [Binary] Binary +# 71| 0: [Integer] 2 +# 71| 1: [ReservedWord] + +# 71| 2: [Integer] 2 +# 71| 2: [ReservedWord] } +# 71| 3: [ReservedWord] " +# 72| 50: [String] String +# 72| 0: [ReservedWord] %Q( +# 72| 1: [StringContent] 3 + 4 = +# 72| 2: [Interpolation] Interpolation +# 72| 0: [ReservedWord] #{ +# 72| 1: [Binary] Binary +# 72| 0: [Integer] 3 +# 72| 1: [ReservedWord] + +# 72| 2: [Integer] 4 +# 72| 2: [ReservedWord] } +# 72| 3: [ReservedWord] ) +# 73| 51: [String] String +# 73| 0: [ReservedWord] ' +# 73| 1: [StringContent] 2 + 2 = #{ 2 + 2 } +# 73| 2: [ReservedWord] ' +# 74| 52: [String] String +# 74| 0: [ReservedWord] %q( +# 74| 1: [StringContent] 3 + 4 = #{ 3 + 4 } +# 74| 2: [ReservedWord] ) +# 75| 53: [ChainedString] ChainedString +# 75| 0: [String] String +# 75| 0: [ReservedWord] " +# 75| 1: [StringContent] foo +# 75| 2: [ReservedWord] " +# 75| 1: [String] String +# 75| 0: [ReservedWord] ' +# 75| 1: [StringContent] bar +# 75| 2: [ReservedWord] ' +# 75| 2: [String] String +# 75| 0: [ReservedWord] " +# 75| 1: [StringContent] baz +# 75| 2: [ReservedWord] " +# 76| 54: [ChainedString] ChainedString +# 76| 0: [String] String +# 76| 0: [ReservedWord] %q{ +# 76| 1: [StringContent] foo +# 76| 2: [ReservedWord] } +# 76| 1: [String] String +# 76| 0: [ReservedWord] " +# 76| 1: [StringContent] bar +# 76| 2: [ReservedWord] " +# 76| 2: [String] String +# 76| 0: [ReservedWord] ' +# 76| 1: [StringContent] baz +# 76| 2: [ReservedWord] ' +# 77| 55: [ChainedString] ChainedString +# 77| 0: [String] String +# 77| 0: [ReservedWord] " +# 77| 1: [StringContent] foo +# 77| 2: [ReservedWord] " +# 77| 1: [String] String +# 77| 0: [ReservedWord] " +# 77| 1: [StringContent] bar +# 77| 2: [Interpolation] Interpolation +# 77| 0: [ReservedWord] #{ +# 77| 1: [Binary] Binary +# 77| 0: [Integer] 1 +# 77| 1: [ReservedWord] * +# 77| 2: [Integer] 1 +# 77| 2: [ReservedWord] } +# 77| 3: [ReservedWord] " +# 77| 2: [String] String +# 77| 0: [ReservedWord] ' +# 77| 1: [StringContent] baz +# 77| 2: [ReservedWord] ' +# 78| 56: [String] String +# 78| 0: [ReservedWord] " +# 78| 1: [StringContent] foo +# 78| 2: [Interpolation] Interpolation +# 78| 0: [ReservedWord] #{ +# 78| 1: [String] String +# 78| 0: [ReservedWord] " +# 78| 1: [StringContent] bar +# 78| 2: [Interpolation] Interpolation +# 78| 0: [ReservedWord] #{ +# 78| 1: [Binary] Binary +# 78| 0: [Integer] 2 +# 78| 1: [ReservedWord] + +# 78| 2: [Integer] 3 +# 78| 2: [ReservedWord] } +# 78| 3: [StringContent] baz +# 78| 4: [ReservedWord] " +# 78| 2: [ReservedWord] } +# 78| 3: [StringContent] qux +# 78| 4: [ReservedWord] " +# 79| 57: [String] String +# 79| 0: [ReservedWord] " +# 79| 1: [StringContent] foo +# 79| 2: [Interpolation] Interpolation +# 79| 0: [ReservedWord] #{ +# 79| 1: [Call] Call +# 79| 0: [Identifier] blah +# 79| 1: [ArgumentList] ArgumentList +# 79| 0: [ReservedWord] ( +# 79| 1: [ReservedWord] ) +# 79| 2: [ReservedWord] ; +# 79| 3: [Binary] Binary +# 79| 0: [Integer] 1 +# 79| 1: [ReservedWord] + +# 79| 2: [Integer] 9 +# 79| 4: [ReservedWord] } +# 79| 3: [ReservedWord] " +# 80| 58: [Assignment] Assignment +# 80| 0: [Identifier] bar +# 80| 1: [ReservedWord] = +# 80| 2: [String] String +# 80| 0: [ReservedWord] " +# 80| 1: [StringContent] bar +# 80| 2: [ReservedWord] " +# 81| 59: [Assignment] Assignment +# 81| 0: [Constant] BAR +# 81| 1: [ReservedWord] = +# 81| 2: [String] String +# 81| 0: [ReservedWord] " +# 81| 1: [StringContent] bar +# 81| 2: [ReservedWord] " +# 82| 60: [String] String +# 82| 0: [ReservedWord] " +# 82| 1: [StringContent] foo +# 82| 2: [Interpolation] Interpolation +# 82| 0: [ReservedWord] #{ +# 82| 1: [Identifier] bar +# 82| 2: [ReservedWord] } +# 82| 3: [ReservedWord] " +# 83| 61: [String] String +# 83| 0: [ReservedWord] " +# 83| 1: [StringContent] foo +# 83| 2: [Interpolation] Interpolation +# 83| 0: [ReservedWord] #{ +# 83| 1: [Constant] BAR +# 83| 2: [ReservedWord] } +# 83| 3: [ReservedWord] " +# 86| 62: [Character] ?x +# 87| 63: [Character] ?\n +# 88| 64: [Character] ?\s +# 89| 65: [Character] ?\\ +# 90| 66: [Character] ?\u{58} +# 91| 67: [Character] ?\C-a +# 92| 68: [Character] ?\M-a +# 93| 69: [Character] ?\M-\C-a +# 94| 70: [Character] ?\C-\M-a +# 97| 71: [DelimitedSymbol] DelimitedSymbol +# 97| 0: [ReservedWord] :" +# 97| 1: [ReservedWord] " +# 98| 72: [SimpleSymbol] :hello +# 99| 73: [DelimitedSymbol] DelimitedSymbol +# 99| 0: [ReservedWord] :" +# 99| 1: [StringContent] foo bar +# 99| 2: [ReservedWord] " +# 100| 74: [DelimitedSymbol] DelimitedSymbol +# 100| 0: [ReservedWord] :' +# 100| 1: [StringContent] bar baz +# 100| 2: [ReservedWord] ' +# 101| 75: [Hash] Hash +# 101| 0: [ReservedWord] { +# 101| 1: [Pair] Pair +# 101| 0: [HashKeySymbol] foo +# 101| 1: [ReservedWord] : +# 101| 2: [String] String +# 101| 0: [ReservedWord] " +# 101| 1: [StringContent] bar +# 101| 2: [ReservedWord] " +# 101| 2: [ReservedWord] } +# 102| 76: [DelimitedSymbol] DelimitedSymbol +# 102| 0: [ReservedWord] %s( +# 102| 1: [StringContent] wibble +# 102| 2: [ReservedWord] ) +# 103| 77: [DelimitedSymbol] DelimitedSymbol +# 103| 0: [ReservedWord] %s[ +# 103| 1: [StringContent] wibble wobble +# 103| 2: [ReservedWord] ] +# 104| 78: [DelimitedSymbol] DelimitedSymbol +# 104| 0: [ReservedWord] :" +# 104| 1: [StringContent] foo_ +# 104| 2: [Interpolation] Interpolation +# 104| 0: [ReservedWord] #{ +# 104| 1: [Binary] Binary +# 104| 0: [Integer] 2 +# 104| 1: [ReservedWord] + +# 104| 2: [Integer] 2 +# 104| 2: [ReservedWord] } +# 104| 3: [StringContent] _ +# 104| 4: [Interpolation] Interpolation +# 104| 0: [ReservedWord] #{ +# 104| 1: [Identifier] bar +# 104| 2: [ReservedWord] } +# 104| 5: [StringContent] _ +# 104| 6: [Interpolation] Interpolation +# 104| 0: [ReservedWord] #{ +# 104| 1: [Constant] BAR +# 104| 2: [ReservedWord] } +# 104| 7: [ReservedWord] " +# 105| 79: [DelimitedSymbol] DelimitedSymbol +# 105| 0: [ReservedWord] :' +# 105| 1: [StringContent] foo_#{ 2 + 2}_#{bar}_#{BAR} +# 105| 2: [ReservedWord] ' +# 106| 80: [DelimitedSymbol] DelimitedSymbol +# 106| 0: [ReservedWord] %s( +# 106| 1: [StringContent] foo_#{ 3 - 2 } +# 106| 2: [ReservedWord] ) +# 109| 81: [Array] Array +# 109| 0: [ReservedWord] [ +# 109| 1: [ReservedWord] ] +# 110| 82: [Array] Array +# 110| 0: [ReservedWord] [ +# 110| 1: [Integer] 1 +# 110| 2: [ReservedWord] , +# 110| 3: [Integer] 2 +# 110| 4: [ReservedWord] , +# 110| 5: [Integer] 3 +# 110| 6: [ReservedWord] ] +# 111| 83: [Array] Array +# 111| 0: [ReservedWord] [ +# 111| 1: [Integer] 4 +# 111| 2: [ReservedWord] , +# 111| 3: [Integer] 5 +# 111| 4: [ReservedWord] , +# 111| 5: [Binary] Binary +# 111| 0: [Integer] 12 +# 111| 1: [ReservedWord] / +# 111| 2: [Integer] 2 +# 111| 6: [ReservedWord] ] +# 112| 84: [Array] Array +# 112| 0: [ReservedWord] [ +# 112| 1: [Integer] 7 +# 112| 2: [ReservedWord] , +# 112| 3: [Array] Array +# 112| 0: [ReservedWord] [ +# 112| 1: [Integer] 8 +# 112| 2: [ReservedWord] , +# 112| 3: [Integer] 9 +# 112| 4: [ReservedWord] ] +# 112| 4: [ReservedWord] ] +# 115| 85: [StringArray] StringArray +# 115| 0: [ReservedWord] %w( +# 115| 1: [ReservedWord] ) +# 116| 86: [StringArray] StringArray +# 116| 0: [ReservedWord] %w( +# 116| 1: [BareString] BareString +# 116| 0: [StringContent] foo +# 116| 2: [BareString] BareString +# 116| 0: [StringContent] bar +# 116| 3: [BareString] BareString +# 116| 0: [StringContent] baz +# 116| 4: [ReservedWord] ) +# 117| 87: [StringArray] StringArray +# 117| 0: [ReservedWord] %w! +# 117| 1: [BareString] BareString +# 117| 0: [StringContent] foo +# 117| 2: [BareString] BareString +# 117| 0: [StringContent] bar +# 117| 3: [BareString] BareString +# 117| 0: [StringContent] baz +# 117| 4: [ReservedWord] ! +# 118| 88: [StringArray] StringArray +# 118| 0: [ReservedWord] %W[ +# 118| 1: [BareString] BareString +# 118| 0: [StringContent] foo +# 118| 2: [BareString] BareString +# 118| 0: [StringContent] bar +# 118| 1: [Interpolation] Interpolation +# 118| 0: [ReservedWord] #{ +# 118| 1: [Binary] Binary +# 118| 0: [Integer] 1 +# 118| 1: [ReservedWord] + +# 118| 2: [Integer] 1 +# 118| 2: [ReservedWord] } +# 118| 3: [BareString] BareString +# 118| 0: [Interpolation] Interpolation +# 118| 0: [ReservedWord] #{ +# 118| 1: [Identifier] bar +# 118| 2: [ReservedWord] } +# 118| 4: [BareString] BareString +# 118| 0: [Interpolation] Interpolation +# 118| 0: [ReservedWord] #{ +# 118| 1: [Constant] BAR +# 118| 2: [ReservedWord] } +# 118| 5: [BareString] BareString +# 118| 0: [StringContent] baz +# 118| 6: [ReservedWord] ] +# 119| 89: [StringArray] StringArray +# 119| 0: [ReservedWord] %w[ +# 119| 1: [BareString] BareString +# 119| 0: [StringContent] foo +# 119| 2: [BareString] BareString +# 119| 0: [StringContent] bar#{1+1} +# 119| 3: [BareString] BareString +# 119| 0: [StringContent] #{bar} +# 119| 4: [BareString] BareString +# 119| 0: [StringContent] #{BAR} +# 119| 5: [BareString] BareString +# 119| 0: [StringContent] baz +# 119| 6: [ReservedWord] ] +# 122| 90: [SymbolArray] SymbolArray +# 122| 0: [ReservedWord] %i( +# 122| 1: [ReservedWord] ) +# 123| 91: [SymbolArray] SymbolArray +# 123| 0: [ReservedWord] %i( +# 123| 1: [BareSymbol] BareSymbol +# 123| 0: [StringContent] foo +# 123| 2: [BareSymbol] BareSymbol +# 123| 0: [StringContent] bar +# 123| 3: [BareSymbol] BareSymbol +# 123| 0: [StringContent] baz +# 123| 4: [ReservedWord] ) +# 124| 92: [SymbolArray] SymbolArray +# 124| 0: [ReservedWord] %i@ +# 124| 1: [BareSymbol] BareSymbol +# 124| 0: [StringContent] foo +# 124| 2: [BareSymbol] BareSymbol +# 124| 0: [StringContent] bar +# 124| 3: [BareSymbol] BareSymbol +# 124| 0: [StringContent] baz +# 124| 4: [ReservedWord] @ +# 125| 93: [SymbolArray] SymbolArray +# 125| 0: [ReservedWord] %I( +# 125| 1: [BareSymbol] BareSymbol +# 125| 0: [StringContent] foo +# 125| 2: [BareSymbol] BareSymbol +# 125| 0: [StringContent] bar +# 125| 1: [Interpolation] Interpolation +# 125| 0: [ReservedWord] #{ +# 125| 1: [Binary] Binary +# 125| 0: [Integer] 2 +# 125| 1: [ReservedWord] + +# 125| 2: [Integer] 4 +# 125| 2: [ReservedWord] } +# 125| 3: [BareSymbol] BareSymbol +# 125| 0: [Interpolation] Interpolation +# 125| 0: [ReservedWord] #{ +# 125| 1: [Identifier] bar +# 125| 2: [ReservedWord] } +# 125| 4: [BareSymbol] BareSymbol +# 125| 0: [Interpolation] Interpolation +# 125| 0: [ReservedWord] #{ +# 125| 1: [Constant] BAR +# 125| 2: [ReservedWord] } +# 125| 5: [BareSymbol] BareSymbol +# 125| 0: [StringContent] baz +# 125| 6: [ReservedWord] ) +# 126| 94: [SymbolArray] SymbolArray +# 126| 0: [ReservedWord] %i( +# 126| 1: [BareSymbol] BareSymbol +# 126| 0: [StringContent] foo +# 126| 2: [BareSymbol] BareSymbol +# 126| 0: [StringContent] bar#{ +# 126| 3: [BareSymbol] BareSymbol +# 126| 0: [StringContent] 2 +# 126| 4: [BareSymbol] BareSymbol +# 126| 0: [StringContent] + +# 126| 5: [BareSymbol] BareSymbol +# 126| 0: [StringContent] 4 +# 126| 6: [BareSymbol] BareSymbol +# 126| 0: [StringContent] } +# 126| 7: [BareSymbol] BareSymbol +# 126| 0: [StringContent] #{bar} +# 126| 8: [BareSymbol] BareSymbol +# 126| 0: [StringContent] #{BAR} +# 126| 9: [BareSymbol] BareSymbol +# 126| 0: [StringContent] baz +# 126| 10: [ReservedWord] ) +# 129| 95: [Hash] Hash +# 129| 0: [ReservedWord] { +# 129| 1: [ReservedWord] } +# 130| 96: [Hash] Hash +# 130| 0: [ReservedWord] { +# 130| 1: [Pair] Pair +# 130| 0: [HashKeySymbol] foo +# 130| 1: [ReservedWord] : +# 130| 2: [Integer] 1 +# 130| 2: [ReservedWord] , +# 130| 3: [Pair] Pair +# 130| 0: [SimpleSymbol] :bar +# 130| 1: [ReservedWord] => +# 130| 2: [Integer] 2 +# 130| 4: [ReservedWord] , +# 130| 5: [Pair] Pair +# 130| 0: [String] String +# 130| 0: [ReservedWord] ' +# 130| 1: [StringContent] baz +# 130| 2: [ReservedWord] ' +# 130| 1: [ReservedWord] => +# 130| 2: [Integer] 3 +# 130| 6: [ReservedWord] } +# 131| 97: [Hash] Hash +# 131| 0: [ReservedWord] { +# 131| 1: [Pair] Pair +# 131| 0: [HashKeySymbol] foo +# 131| 1: [ReservedWord] : +# 131| 2: [Integer] 7 +# 131| 2: [ReservedWord] , +# 131| 3: [HashSplatArgument] HashSplatArgument +# 131| 0: [ReservedWord] ** +# 131| 1: [Identifier] baz +# 131| 4: [ReservedWord] } +# 134| 98: [ParenthesizedStatements] ParenthesizedStatements +# 134| 0: [ReservedWord] ( +# 134| 1: [Range] Range +# 134| 0: [Integer] 1 +# 134| 1: [ReservedWord] .. +# 134| 2: [Integer] 10 +# 134| 2: [ReservedWord] ) +# 135| 99: [ParenthesizedStatements] ParenthesizedStatements +# 135| 0: [ReservedWord] ( +# 135| 1: [Range] Range +# 135| 0: [Integer] 1 +# 135| 1: [ReservedWord] ... +# 135| 2: [Integer] 10 +# 135| 2: [ReservedWord] ) +# 136| 100: [ParenthesizedStatements] ParenthesizedStatements +# 136| 0: [ReservedWord] ( +# 136| 1: [Range] Range +# 136| 0: [Integer] 1 +# 136| 1: [ReservedWord] .. +# 136| 2: [Integer] 0 +# 136| 2: [ReservedWord] ) +# 137| 101: [ParenthesizedStatements] ParenthesizedStatements +# 137| 0: [ReservedWord] ( +# 137| 1: [Range] Range +# 137| 0: [Identifier] start +# 137| 1: [ReservedWord] .. +# 137| 2: [Binary] Binary +# 137| 0: [Integer] 2 +# 137| 1: [ReservedWord] + +# 137| 2: [Integer] 3 +# 137| 2: [ReservedWord] ) +# 138| 102: [ParenthesizedStatements] ParenthesizedStatements +# 138| 0: [ReservedWord] ( +# 138| 1: [Range] Range +# 138| 0: [Integer] 1 +# 138| 1: [ReservedWord] .. +# 138| 2: [ReservedWord] ) +# 139| 103: [ParenthesizedStatements] ParenthesizedStatements +# 139| 0: [ReservedWord] ( +# 139| 1: [Range] Range +# 139| 0: [ReservedWord] .. +# 139| 1: [Integer] 1 +# 139| 2: [ReservedWord] ) +# 140| 104: [ParenthesizedStatements] ParenthesizedStatements +# 140| 0: [ReservedWord] ( +# 140| 1: [Binary] Binary +# 140| 0: [Range] Range +# 140| 0: [Integer] 0 +# 140| 1: [ReservedWord] .. +# 140| 1: [ReservedWord] - +# 140| 2: [Integer] 1 +# 140| 2: [ReservedWord] ) +# 143| 105: [Subshell] Subshell +# 143| 0: [ReservedWord] ` +# 143| 1: [StringContent] ls -l +# 143| 2: [ReservedWord] ` +# 144| 106: [Subshell] Subshell +# 144| 0: [ReservedWord] %x( +# 144| 1: [StringContent] ls -l +# 144| 2: [ReservedWord] ) +# 145| 107: [Subshell] Subshell +# 145| 0: [ReservedWord] ` +# 145| 1: [StringContent] du -d +# 145| 2: [Interpolation] Interpolation +# 145| 0: [ReservedWord] #{ +# 145| 1: [Binary] Binary +# 145| 0: [Integer] 1 +# 145| 1: [ReservedWord] + +# 145| 2: [Integer] 1 +# 145| 2: [ReservedWord] } +# 145| 3: [StringContent] +# 145| 4: [Interpolation] Interpolation +# 145| 0: [ReservedWord] #{ +# 145| 1: [Identifier] bar +# 145| 2: [ReservedWord] } +# 145| 5: [StringContent] +# 145| 6: [Interpolation] Interpolation +# 145| 0: [ReservedWord] #{ +# 145| 1: [Constant] BAR +# 145| 2: [ReservedWord] } +# 145| 7: [ReservedWord] ` +# 146| 108: [Subshell] Subshell +# 146| 0: [ReservedWord] %x@ +# 146| 1: [StringContent] du -d +# 146| 2: [Interpolation] Interpolation +# 146| 0: [ReservedWord] #{ +# 146| 1: [Binary] Binary +# 146| 0: [Integer] 5 +# 146| 1: [ReservedWord] - +# 146| 2: [Integer] 4 +# 146| 2: [ReservedWord] } +# 146| 3: [ReservedWord] @ +# 149| 109: [Regex] Regex +# 149| 0: [ReservedWord] / +# 149| 1: [ReservedWord] / +# 150| 110: [Regex] Regex +# 150| 0: [ReservedWord] / +# 150| 1: [StringContent] foo +# 150| 2: [ReservedWord] / +# 151| 111: [Regex] Regex +# 151| 0: [ReservedWord] / +# 151| 1: [StringContent] foo +# 151| 2: [ReservedWord] /i +# 152| 112: [Regex] Regex +# 152| 0: [ReservedWord] / +# 152| 1: [StringContent] foo+ +# 152| 2: [EscapeSequence] \s +# 152| 3: [StringContent] bar +# 152| 4: [EscapeSequence] \S +# 152| 5: [ReservedWord] / +# 153| 113: [Regex] Regex +# 153| 0: [ReservedWord] / +# 153| 1: [StringContent] foo +# 153| 2: [Interpolation] Interpolation +# 153| 0: [ReservedWord] #{ +# 153| 1: [Binary] Binary +# 153| 0: [Integer] 1 +# 153| 1: [ReservedWord] + +# 153| 2: [Integer] 1 +# 153| 2: [ReservedWord] } +# 153| 3: [StringContent] bar +# 153| 4: [Interpolation] Interpolation +# 153| 0: [ReservedWord] #{ +# 153| 1: [Identifier] bar +# 153| 2: [ReservedWord] } +# 153| 5: [Interpolation] Interpolation +# 153| 0: [ReservedWord] #{ +# 153| 1: [Constant] BAR +# 153| 2: [ReservedWord] } +# 153| 6: [ReservedWord] / +# 154| 114: [Regex] Regex +# 154| 0: [ReservedWord] / +# 154| 1: [StringContent] foo +# 154| 2: [ReservedWord] /oxm +# 155| 115: [Regex] Regex +# 155| 0: [ReservedWord] %r[ +# 155| 1: [ReservedWord] ] +# 156| 116: [Regex] Regex +# 156| 0: [ReservedWord] %r( +# 156| 1: [StringContent] foo +# 156| 2: [ReservedWord] ) +# 157| 117: [Regex] Regex +# 157| 0: [ReservedWord] %r: +# 157| 1: [StringContent] foo +# 157| 2: [ReservedWord] :i +# 158| 118: [Regex] Regex +# 158| 0: [ReservedWord] %r{ +# 158| 1: [StringContent] foo+ +# 158| 2: [EscapeSequence] \s +# 158| 3: [StringContent] bar +# 158| 4: [EscapeSequence] \S +# 158| 5: [ReservedWord] } +# 159| 119: [Regex] Regex +# 159| 0: [ReservedWord] %r{ +# 159| 1: [StringContent] foo +# 159| 2: [Interpolation] Interpolation +# 159| 0: [ReservedWord] #{ +# 159| 1: [Binary] Binary +# 159| 0: [Integer] 1 +# 159| 1: [ReservedWord] + +# 159| 2: [Integer] 1 +# 159| 2: [ReservedWord] } +# 159| 3: [StringContent] bar +# 159| 4: [Interpolation] Interpolation +# 159| 0: [ReservedWord] #{ +# 159| 1: [Identifier] bar +# 159| 2: [ReservedWord] } +# 159| 5: [Interpolation] Interpolation +# 159| 0: [ReservedWord] #{ +# 159| 1: [Constant] BAR +# 159| 2: [ReservedWord] } +# 159| 6: [ReservedWord] } +# 160| 120: [Regex] Regex +# 160| 0: [ReservedWord] %r: +# 160| 1: [StringContent] foo +# 160| 2: [ReservedWord] :mxo +# 163| 121: [String] String +# 163| 0: [ReservedWord] ' +# 163| 1: [StringContent] abcdefghijklmnopqrstuvwxyzabcdef +# 163| 2: [ReservedWord] ' +# 164| 122: [String] String +# 164| 0: [ReservedWord] ' +# 164| 1: [StringContent] foobarfoobarfoobarfoobarfoobarfoo +# 164| 2: [ReservedWord] ' +# 165| 123: [String] String +# 165| 0: [ReservedWord] " +# 165| 1: [StringContent] foobar +# 165| 2: [EscapeSequence] \\ +# 165| 3: [StringContent] foobar +# 165| 4: [EscapeSequence] \\ +# 165| 5: [StringContent] foobar +# 165| 6: [EscapeSequence] \\ +# 165| 7: [StringContent] foobar +# 165| 8: [EscapeSequence] \\ +# 165| 9: [StringContent] foobar +# 165| 10: [ReservedWord] " +# 168| 124: [Call] Call +# 168| 0: [Identifier] run_sql +# 168| 1: [ArgumentList] ArgumentList +# 168| 0: [ReservedWord] ( +# 168| 1: [HeredocBeginning] <> +# 47| 2: [Integer] 16 +# 48| 37: [Binary] Binary +# 48| 0: [Identifier] foo +# 48| 1: [ReservedWord] & +# 48| 2: [Integer] 0xff +# 49| 38: [Binary] Binary +# 49| 0: [Identifier] bar +# 49| 1: [ReservedWord] | +# 49| 2: [Integer] 0x02 +# 50| 39: [Binary] Binary +# 50| 0: [Identifier] baz +# 50| 1: [ReservedWord] ^ +# 50| 2: [Identifier] qux +# 53| 40: [Binary] Binary +# 53| 0: [Identifier] x +# 53| 1: [ReservedWord] == +# 53| 2: [Identifier] y +# 54| 41: [Binary] Binary +# 54| 0: [Identifier] a +# 54| 1: [ReservedWord] != +# 54| 2: [Integer] 123 +# 55| 42: [Binary] Binary +# 55| 0: [Identifier] m +# 55| 1: [ReservedWord] === +# 55| 2: [Identifier] n +# 58| 43: [Binary] Binary +# 58| 0: [Identifier] x +# 58| 1: [ReservedWord] > +# 58| 2: [Integer] 0 +# 59| 44: [Binary] Binary +# 59| 0: [Identifier] y +# 59| 1: [ReservedWord] >= +# 59| 2: [Integer] 100 +# 60| 45: [Binary] Binary +# 60| 0: [Identifier] a +# 60| 1: [ReservedWord] < +# 60| 2: [Identifier] b +# 61| 46: [Binary] Binary +# 61| 0: [Integer] 7 +# 61| 1: [ReservedWord] <= +# 61| 2: [Identifier] foo +# 64| 47: [Binary] Binary +# 64| 0: [Identifier] a +# 64| 1: [ReservedWord] <=> +# 64| 2: [Identifier] b +# 65| 48: [Binary] Binary +# 65| 0: [Identifier] name +# 65| 1: [ReservedWord] =~ +# 65| 2: [Regex] Regex +# 65| 0: [ReservedWord] / +# 65| 1: [StringContent] foo.* +# 65| 2: [ReservedWord] / +# 66| 49: [Binary] Binary +# 66| 0: [Identifier] handle +# 66| 1: [ReservedWord] !~ +# 66| 2: [Regex] Regex +# 66| 0: [ReservedWord] / +# 66| 1: [StringContent] .*bar +# 66| 2: [ReservedWord] / +# 69| 50: [OperatorAssignment] OperatorAssignment +# 69| 0: [Identifier] x +# 69| 1: [ReservedWord] += +# 69| 2: [Integer] 128 +# 70| 51: [OperatorAssignment] OperatorAssignment +# 70| 0: [Identifier] y +# 70| 1: [ReservedWord] -= +# 70| 2: [Integer] 32 +# 71| 52: [OperatorAssignment] OperatorAssignment +# 71| 0: [Identifier] a +# 71| 1: [ReservedWord] *= +# 71| 2: [Integer] 12 +# 72| 53: [OperatorAssignment] OperatorAssignment +# 72| 0: [Identifier] b +# 72| 1: [ReservedWord] /= +# 72| 2: [Integer] 4 +# 73| 54: [OperatorAssignment] OperatorAssignment +# 73| 0: [Identifier] z +# 73| 1: [ReservedWord] %= +# 73| 2: [Integer] 2 +# 74| 55: [OperatorAssignment] OperatorAssignment +# 74| 0: [Identifier] foo +# 74| 1: [ReservedWord] **= +# 74| 2: [Identifier] bar +# 77| 56: [OperatorAssignment] OperatorAssignment +# 77| 0: [Identifier] x +# 77| 1: [ReservedWord] &&= +# 77| 2: [Identifier] y +# 78| 57: [OperatorAssignment] OperatorAssignment +# 78| 0: [Identifier] a +# 78| 1: [ReservedWord] ||= +# 78| 2: [Identifier] b +# 81| 58: [OperatorAssignment] OperatorAssignment +# 81| 0: [Identifier] x +# 81| 1: [ReservedWord] <<= +# 81| 2: [Integer] 2 +# 82| 59: [OperatorAssignment] OperatorAssignment +# 82| 0: [Identifier] y +# 82| 1: [ReservedWord] >>= +# 82| 2: [Integer] 3 +# 83| 60: [OperatorAssignment] OperatorAssignment +# 83| 0: [Identifier] foo +# 83| 1: [ReservedWord] &= +# 83| 2: [Identifier] mask +# 84| 61: [OperatorAssignment] OperatorAssignment +# 84| 0: [Identifier] bar +# 84| 1: [ReservedWord] |= +# 84| 2: [Integer] 0x01 +# 85| 62: [OperatorAssignment] OperatorAssignment +# 85| 0: [Identifier] baz +# 85| 1: [ReservedWord] ^= +# 85| 2: [Identifier] qux +# 87| 63: [Class] Class +# 87| 0: [ReservedWord] class +# 87| 1: [Constant] X +# 88| 2: [Assignment] Assignment +# 88| 0: [InstanceVariable] @x +# 88| 1: [ReservedWord] = +# 88| 2: [Integer] 1 +# 89| 3: [OperatorAssignment] OperatorAssignment +# 89| 0: [InstanceVariable] @x +# 89| 1: [ReservedWord] += +# 89| 2: [Integer] 2 +# 91| 4: [Assignment] Assignment +# 91| 0: [ClassVariable] @@y +# 91| 1: [ReservedWord] = +# 91| 2: [Integer] 3 +# 92| 5: [OperatorAssignment] OperatorAssignment +# 92| 0: [ClassVariable] @@y +# 92| 1: [ReservedWord] /= +# 92| 2: [Integer] 4 +# 93| 6: [ReservedWord] end +# 95| 64: [Assignment] Assignment +# 95| 0: [GlobalVariable] $global_var +# 95| 1: [ReservedWord] = +# 95| 2: [Integer] 5 +# 96| 65: [OperatorAssignment] OperatorAssignment +# 96| 0: [GlobalVariable] $global_var +# 96| 1: [ReservedWord] *= +# 96| 2: [Integer] 6 +# 1| [Comment] # Start with assignments to all the identifiers used below, so that they are +# 2| [Comment] # interpreted as variables. +# 22| [Comment] # Unary operations +# 31| [Comment] # Binary arithmetic operations +# 39| [Comment] # Binary logical operations +# 45| [Comment] # Binary bitwise operations +# 52| [Comment] # Equality operations +# 57| [Comment] # Relational operations +# 63| [Comment] # Misc binary operations +# 68| [Comment] # Arithmetic assign operations +# 76| [Comment] # Logical assign operations +# 80| [Comment] # Bitwise assign operations +params/params.rb: +# 1| [Program] Program +# 4| 0: [Method] Method +# 4| 0: [ReservedWord] def +# 4| 1: [Identifier] identifier_method_params +# 4| 2: [MethodParameters] MethodParameters +# 4| 0: [ReservedWord] ( +# 4| 1: [Identifier] foo +# 4| 2: [ReservedWord] , +# 4| 3: [Identifier] bar +# 4| 4: [ReservedWord] , +# 4| 5: [Identifier] baz +# 4| 6: [ReservedWord] ) +# 5| 3: [ReservedWord] end +# 8| 1: [Assignment] Assignment +# 8| 0: [Identifier] hash +# 8| 1: [ReservedWord] = +# 8| 2: [Hash] Hash +# 8| 0: [ReservedWord] { +# 8| 1: [ReservedWord] } +# 9| 2: [Call] Call +# 9| 0: [Identifier] hash +# 9| 1: [ReservedWord] . +# 9| 2: [Identifier] each +# 9| 3: [DoBlock] DoBlock +# 9| 0: [ReservedWord] do +# 9| 1: [BlockParameters] BlockParameters +# 9| 0: [ReservedWord] | +# 9| 1: [Identifier] key +# 9| 2: [ReservedWord] , +# 9| 3: [Identifier] value +# 9| 4: [ReservedWord] | +# 10| 2: [Call] Call +# 10| 0: [Identifier] puts +# 10| 1: [ArgumentList] ArgumentList +# 10| 0: [String] String +# 10| 0: [ReservedWord] " +# 10| 1: [Interpolation] Interpolation +# 10| 0: [ReservedWord] #{ +# 10| 1: [Identifier] key +# 10| 2: [ReservedWord] } +# 10| 2: [StringContent] -> +# 10| 3: [Interpolation] Interpolation +# 10| 0: [ReservedWord] #{ +# 10| 1: [Identifier] value +# 10| 2: [ReservedWord] } +# 10| 4: [ReservedWord] " +# 11| 3: [ReservedWord] end +# 14| 3: [Assignment] Assignment +# 14| 0: [Identifier] sum +# 14| 1: [ReservedWord] = +# 14| 2: [Lambda] Lambda +# 14| 0: [ReservedWord] -> +# 14| 1: [LambdaParameters] LambdaParameters +# 14| 0: [ReservedWord] ( +# 14| 1: [Identifier] foo +# 14| 2: [ReservedWord] , +# 14| 3: [Identifier] bar +# 14| 4: [ReservedWord] ) +# 14| 2: [Block] Block +# 14| 0: [ReservedWord] { +# 14| 1: [Binary] Binary +# 14| 0: [Identifier] foo +# 14| 1: [ReservedWord] + +# 14| 2: [Identifier] bar +# 14| 2: [ReservedWord] } +# 17| 4: [Method] Method +# 17| 0: [ReservedWord] def +# 17| 1: [Identifier] destructured_method_param +# 17| 2: [MethodParameters] MethodParameters +# 17| 0: [ReservedWord] ( +# 17| 1: [DestructuredParameter] DestructuredParameter +# 17| 0: [ReservedWord] ( +# 17| 1: [Identifier] a +# 17| 2: [ReservedWord] , +# 17| 3: [Identifier] b +# 17| 4: [ReservedWord] , +# 17| 5: [Identifier] c +# 17| 6: [ReservedWord] ) +# 17| 2: [ReservedWord] ) +# 18| 3: [ReservedWord] end +# 21| 5: [Assignment] Assignment +# 21| 0: [Identifier] array +# 21| 1: [ReservedWord] = +# 21| 2: [Array] Array +# 21| 0: [ReservedWord] [ +# 21| 1: [ReservedWord] ] +# 22| 6: [Call] Call +# 22| 0: [Identifier] array +# 22| 1: [ReservedWord] . +# 22| 2: [Identifier] each +# 22| 3: [Block] Block +# 22| 0: [ReservedWord] { +# 22| 1: [BlockParameters] BlockParameters +# 22| 0: [ReservedWord] | +# 22| 1: [DestructuredParameter] DestructuredParameter +# 22| 0: [ReservedWord] ( +# 22| 1: [Identifier] a +# 22| 2: [ReservedWord] , +# 22| 3: [Identifier] b +# 22| 4: [ReservedWord] ) +# 22| 2: [ReservedWord] | +# 22| 2: [Call] Call +# 22| 0: [Identifier] puts +# 22| 1: [ArgumentList] ArgumentList +# 22| 0: [Binary] Binary +# 22| 0: [Identifier] a +# 22| 1: [ReservedWord] + +# 22| 2: [Identifier] b +# 22| 3: [ReservedWord] } +# 25| 7: [Assignment] Assignment +# 25| 0: [Identifier] sum_four_values +# 25| 1: [ReservedWord] = +# 25| 2: [Lambda] Lambda +# 25| 0: [ReservedWord] -> +# 25| 1: [LambdaParameters] LambdaParameters +# 25| 0: [ReservedWord] ( +# 25| 1: [DestructuredParameter] DestructuredParameter +# 25| 0: [ReservedWord] ( +# 25| 1: [Identifier] first +# 25| 2: [ReservedWord] , +# 25| 3: [Identifier] second +# 25| 4: [ReservedWord] ) +# 25| 2: [ReservedWord] , +# 25| 3: [DestructuredParameter] DestructuredParameter +# 25| 0: [ReservedWord] ( +# 25| 1: [Identifier] third +# 25| 2: [ReservedWord] , +# 25| 3: [Identifier] fourth +# 25| 4: [ReservedWord] ) +# 25| 4: [ReservedWord] ) +# 25| 2: [Block] Block +# 25| 0: [ReservedWord] { +# 26| 1: [Binary] Binary +# 26| 0: [Binary] Binary +# 26| 0: [Binary] Binary +# 26| 0: [Identifier] first +# 26| 1: [ReservedWord] + +# 26| 2: [Identifier] second +# 26| 1: [ReservedWord] + +# 26| 2: [Identifier] third +# 26| 1: [ReservedWord] + +# 26| 2: [Identifier] fourth +# 27| 2: [ReservedWord] } +# 30| 8: [Method] Method +# 30| 0: [ReservedWord] def +# 30| 1: [Identifier] method_with_splat +# 30| 2: [MethodParameters] MethodParameters +# 30| 0: [ReservedWord] ( +# 30| 1: [Identifier] wibble +# 30| 2: [ReservedWord] , +# 30| 3: [SplatParameter] SplatParameter +# 30| 0: [ReservedWord] * +# 30| 1: [Identifier] splat +# 30| 4: [ReservedWord] , +# 30| 5: [HashSplatParameter] HashSplatParameter +# 30| 0: [ReservedWord] ** +# 30| 1: [Identifier] double_splat +# 30| 6: [ReservedWord] ) +# 31| 3: [ReservedWord] end +# 34| 9: [Call] Call +# 34| 0: [Identifier] array +# 34| 1: [ReservedWord] . +# 34| 2: [Identifier] each +# 34| 3: [DoBlock] DoBlock +# 34| 0: [ReservedWord] do +# 34| 1: [BlockParameters] BlockParameters +# 34| 0: [ReservedWord] | +# 34| 1: [Identifier] val +# 34| 2: [ReservedWord] , +# 34| 3: [SplatParameter] SplatParameter +# 34| 0: [ReservedWord] * +# 34| 1: [Identifier] splat +# 34| 4: [ReservedWord] , +# 34| 5: [HashSplatParameter] HashSplatParameter +# 34| 0: [ReservedWord] ** +# 34| 1: [Identifier] double_splat +# 34| 6: [ReservedWord] | +# 35| 2: [ReservedWord] end +# 38| 10: [Assignment] Assignment +# 38| 0: [Identifier] lambda_with_splats +# 38| 1: [ReservedWord] = +# 38| 2: [Lambda] Lambda +# 38| 0: [ReservedWord] -> +# 38| 1: [LambdaParameters] LambdaParameters +# 38| 0: [ReservedWord] ( +# 38| 1: [Identifier] x +# 38| 2: [ReservedWord] , +# 38| 3: [SplatParameter] SplatParameter +# 38| 0: [ReservedWord] * +# 38| 1: [Identifier] blah +# 38| 4: [ReservedWord] , +# 38| 5: [HashSplatParameter] HashSplatParameter +# 38| 0: [ReservedWord] ** +# 38| 1: [Identifier] wibble +# 38| 6: [ReservedWord] ) +# 38| 2: [Block] Block +# 38| 0: [ReservedWord] { +# 38| 1: [ReservedWord] } +# 41| 11: [Method] Method +# 41| 0: [ReservedWord] def +# 41| 1: [Identifier] method_with_keyword_params +# 41| 2: [MethodParameters] MethodParameters +# 41| 0: [ReservedWord] ( +# 41| 1: [Identifier] x +# 41| 2: [ReservedWord] , +# 41| 3: [KeywordParameter] KeywordParameter +# 41| 0: [Identifier] foo +# 41| 1: [ReservedWord] : +# 41| 4: [ReservedWord] , +# 41| 5: [KeywordParameter] KeywordParameter +# 41| 0: [Identifier] bar +# 41| 1: [ReservedWord] : +# 41| 2: [Integer] 7 +# 41| 6: [ReservedWord] ) +# 42| 3: [Binary] Binary +# 42| 0: [Binary] Binary +# 42| 0: [Identifier] x +# 42| 1: [ReservedWord] + +# 42| 2: [Identifier] foo +# 42| 1: [ReservedWord] + +# 42| 2: [Identifier] bar +# 43| 4: [ReservedWord] end +# 46| 12: [Method] Method +# 46| 0: [ReservedWord] def +# 46| 1: [Identifier] use_block_with_keyword +# 46| 2: [MethodParameters] MethodParameters +# 46| 0: [ReservedWord] ( +# 46| 1: [BlockParameter] BlockParameter +# 46| 0: [ReservedWord] & +# 46| 1: [Identifier] block +# 46| 2: [ReservedWord] ) +# 47| 3: [Call] Call +# 47| 0: [Identifier] puts +# 47| 1: [ArgumentList] ArgumentList +# 47| 0: [ReservedWord] ( +# 47| 1: [Call] Call +# 47| 0: [Identifier] block +# 47| 1: [ReservedWord] . +# 47| 2: [Identifier] call +# 47| 3: [ArgumentList] ArgumentList +# 47| 0: [Pair] Pair +# 47| 0: [HashKeySymbol] bar +# 47| 1: [ReservedWord] : +# 47| 2: [Integer] 2 +# 47| 1: [ReservedWord] , +# 47| 2: [Pair] Pair +# 47| 0: [HashKeySymbol] foo +# 47| 1: [ReservedWord] : +# 47| 2: [Integer] 3 +# 47| 2: [ReservedWord] ) +# 48| 4: [ReservedWord] end +# 49| 13: [Call] Call +# 49| 0: [Identifier] use_block_with_keyword +# 49| 1: [DoBlock] DoBlock +# 49| 0: [ReservedWord] do +# 49| 1: [BlockParameters] BlockParameters +# 49| 0: [ReservedWord] | +# 49| 1: [KeywordParameter] KeywordParameter +# 49| 0: [Identifier] xx +# 49| 1: [ReservedWord] : +# 49| 2: [ReservedWord] , +# 49| 3: [KeywordParameter] KeywordParameter +# 49| 0: [Identifier] yy +# 49| 1: [ReservedWord] : +# 49| 2: [Integer] 100 +# 49| 4: [ReservedWord] | +# 50| 2: [Binary] Binary +# 50| 0: [Identifier] xx +# 50| 1: [ReservedWord] + +# 50| 2: [Identifier] yy +# 51| 3: [ReservedWord] end +# 53| 14: [Assignment] Assignment +# 53| 0: [Identifier] lambda_with_keyword_params +# 53| 1: [ReservedWord] = +# 53| 2: [Lambda] Lambda +# 53| 0: [ReservedWord] -> +# 53| 1: [LambdaParameters] LambdaParameters +# 53| 0: [ReservedWord] ( +# 53| 1: [Identifier] x +# 53| 2: [ReservedWord] , +# 53| 3: [KeywordParameter] KeywordParameter +# 53| 0: [Identifier] y +# 53| 1: [ReservedWord] : +# 53| 4: [ReservedWord] , +# 53| 5: [KeywordParameter] KeywordParameter +# 53| 0: [Identifier] z +# 53| 1: [ReservedWord] : +# 53| 2: [Integer] 3 +# 53| 6: [ReservedWord] ) +# 53| 2: [Block] Block +# 53| 0: [ReservedWord] { +# 54| 1: [Binary] Binary +# 54| 0: [Binary] Binary +# 54| 0: [Identifier] x +# 54| 1: [ReservedWord] + +# 54| 2: [Identifier] y +# 54| 1: [ReservedWord] + +# 54| 2: [Identifier] z +# 55| 2: [ReservedWord] } +# 58| 15: [Method] Method +# 58| 0: [ReservedWord] def +# 58| 1: [Identifier] method_with_optional_params +# 58| 2: [MethodParameters] MethodParameters +# 58| 0: [ReservedWord] ( +# 58| 1: [Identifier] val1 +# 58| 2: [ReservedWord] , +# 58| 3: [OptionalParameter] OptionalParameter +# 58| 0: [Identifier] val2 +# 58| 1: [ReservedWord] = +# 58| 2: [Integer] 0 +# 58| 4: [ReservedWord] , +# 58| 5: [OptionalParameter] OptionalParameter +# 58| 0: [Identifier] val3 +# 58| 1: [ReservedWord] = +# 58| 2: [Integer] 100 +# 58| 6: [ReservedWord] ) +# 59| 3: [ReservedWord] end +# 62| 16: [Method] Method +# 62| 0: [ReservedWord] def +# 62| 1: [Identifier] use_block_with_optional +# 62| 2: [MethodParameters] MethodParameters +# 62| 0: [ReservedWord] ( +# 62| 1: [BlockParameter] BlockParameter +# 62| 0: [ReservedWord] & +# 62| 1: [Identifier] block +# 62| 2: [ReservedWord] ) +# 63| 3: [Call] Call +# 63| 0: [Identifier] block +# 63| 1: [ReservedWord] . +# 63| 2: [Identifier] call +# 63| 3: [ArgumentList] ArgumentList +# 63| 0: [String] String +# 63| 0: [ReservedWord] ' +# 63| 1: [StringContent] Zeus +# 63| 2: [ReservedWord] ' +# 64| 4: [ReservedWord] end +# 65| 17: [Call] Call +# 65| 0: [Identifier] use_block_with_optional +# 65| 1: [DoBlock] DoBlock +# 65| 0: [ReservedWord] do +# 65| 1: [BlockParameters] BlockParameters +# 65| 0: [ReservedWord] | +# 65| 1: [Identifier] name +# 65| 2: [ReservedWord] , +# 65| 3: [OptionalParameter] OptionalParameter +# 65| 0: [Identifier] age +# 65| 1: [ReservedWord] = +# 65| 2: [Integer] 99 +# 65| 4: [ReservedWord] | +# 66| 2: [Call] Call +# 66| 0: [Identifier] puts +# 66| 1: [ArgumentList] ArgumentList +# 66| 0: [String] String +# 66| 0: [ReservedWord] " +# 66| 1: [Interpolation] Interpolation +# 66| 0: [ReservedWord] #{ +# 66| 1: [Identifier] name +# 66| 2: [ReservedWord] } +# 66| 2: [StringContent] is +# 66| 3: [Interpolation] Interpolation +# 66| 0: [ReservedWord] #{ +# 66| 1: [Identifier] age +# 66| 2: [ReservedWord] } +# 66| 4: [StringContent] years old +# 66| 5: [ReservedWord] " +# 67| 3: [ReservedWord] end +# 70| 18: [Assignment] Assignment +# 70| 0: [Identifier] lambda_with_optional_params +# 70| 1: [ReservedWord] = +# 70| 2: [Lambda] Lambda +# 70| 0: [ReservedWord] -> +# 70| 1: [LambdaParameters] LambdaParameters +# 70| 0: [ReservedWord] ( +# 70| 1: [Identifier] a +# 70| 2: [ReservedWord] , +# 70| 3: [OptionalParameter] OptionalParameter +# 70| 0: [Identifier] b +# 70| 1: [ReservedWord] = +# 70| 2: [Integer] 1000 +# 70| 4: [ReservedWord] , +# 70| 5: [OptionalParameter] OptionalParameter +# 70| 0: [Identifier] c +# 70| 1: [ReservedWord] = +# 70| 2: [Integer] 20 +# 70| 6: [ReservedWord] ) +# 70| 2: [Block] Block +# 70| 0: [ReservedWord] { +# 70| 1: [Binary] Binary +# 70| 0: [Binary] Binary +# 70| 0: [Identifier] a +# 70| 1: [ReservedWord] + +# 70| 2: [Identifier] b +# 70| 1: [ReservedWord] + +# 70| 2: [Identifier] c +# 70| 2: [ReservedWord] } +# 73| 19: [Method] Method +# 73| 0: [ReservedWord] def +# 73| 1: [Identifier] method_with_nil_splat +# 73| 2: [MethodParameters] MethodParameters +# 73| 0: [ReservedWord] ( +# 73| 1: [Identifier] wibble +# 73| 2: [ReservedWord] , +# 73| 3: [HashSplatNil] **nil +# 73| 0: [ReservedWord] ** +# 73| 1: [ReservedWord] nil +# 73| 4: [ReservedWord] ) +# 74| 3: [ReservedWord] end +# 77| 20: [Call] Call +# 77| 0: [Identifier] array +# 77| 1: [ReservedWord] . +# 77| 2: [Identifier] each +# 77| 3: [DoBlock] DoBlock +# 77| 0: [ReservedWord] do +# 77| 1: [BlockParameters] BlockParameters +# 77| 0: [ReservedWord] | +# 77| 1: [Identifier] val +# 77| 2: [ReservedWord] , +# 77| 3: [HashSplatNil] **nil +# 77| 0: [ReservedWord] ** +# 77| 1: [ReservedWord] nil +# 77| 4: [ReservedWord] | +# 78| 2: [ReservedWord] end +# 81| 21: [Method] Method +# 81| 0: [ReservedWord] def +# 81| 1: [Identifier] anonymous_block_parameter +# 81| 2: [MethodParameters] MethodParameters +# 81| 0: [ReservedWord] ( +# 81| 1: [Identifier] array +# 81| 2: [ReservedWord] , +# 81| 3: [BlockParameter] BlockParameter +# 81| 0: [ReservedWord] & +# 81| 4: [ReservedWord] ) +# 82| 3: [Call] Call +# 82| 0: [Identifier] proc +# 82| 1: [ArgumentList] ArgumentList +# 82| 0: [ReservedWord] ( +# 82| 1: [BlockArgument] BlockArgument +# 82| 0: [ReservedWord] & +# 82| 2: [ReservedWord] ) +# 83| 4: [Call] Call +# 83| 0: [Identifier] array +# 83| 1: [ReservedWord] . +# 83| 2: [Identifier] each +# 83| 3: [ArgumentList] ArgumentList +# 83| 0: [ReservedWord] ( +# 83| 1: [BlockArgument] BlockArgument +# 83| 0: [ReservedWord] & +# 83| 2: [ReservedWord] ) +# 84| 5: [ReservedWord] end +# 1| [Comment] # Tests for the different kinds and contexts of parameters. +# 3| [Comment] # Method containing identifier parameters +# 7| [Comment] # Block containing identifier parameters +# 13| [Comment] # Lambda containing identifier parameters +# 16| [Comment] # Method containing destructured parameters +# 20| [Comment] # Block containing destructured parameters +# 24| [Comment] # Lambda containing destructured parameters +# 29| [Comment] # Method containing splat and hash-splat params +# 33| [Comment] # Block with splat and hash-splat parameter +# 37| [Comment] # Lambda with splat and hash-splat +# 40| [Comment] # Method containing keyword parameters +# 45| [Comment] # Block with keyword parameters +# 57| [Comment] # Method containing optional parameters +# 61| [Comment] # Block containing optional parameter +# 69| [Comment] # Lambda containing optional parameters +# 72| [Comment] # Method containing nil hash-splat params +# 76| [Comment] # Block with nil hash-splat parameter +# 80| [Comment] # Anonymous block parameter diff --git a/ruby/ql/test/library-tests/ast/TreeSitter.ql b/ruby/ql/test/library-tests/ast/TreeSitter.ql new file mode 100644 index 00000000000..19ef2794188 --- /dev/null +++ b/ruby/ql/test/library-tests/ast/TreeSitter.ql @@ -0,0 +1,31 @@ +/** + * @kind graph + */ + +import codeql.ruby.ast.internal.TreeSitter::Ruby + +/** + * Holds if `node` belongs to the output tree, and its property `key` has the + * given `value`. + */ +query predicate nodes(AstNode node, string key, string value) { + key = "semmle.label" and + value = "[" + node.getPrimaryQlClasses() + "] " + node.toString() +} + +/** + * Holds if `target` is a child of `source` in the AST, and property `key` of + * the edge has the given `value`. + */ +query predicate edges(AstNode source, AstNode target, string key, string value) { + source = target.getParent() and + key = ["semmle.label", "semmle.order"] and + value = target.getParentIndex().toString() +} + +/** + * Holds if property `key` of the graph has the given `value`. + */ +query predicate graphProperties(string key, string value) { + key = "semmle.graphKind" and value = "tree" +} From 0d9354322e320eb1f29bbb25bfd38de969cc40c9 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Tue, 26 Apr 2022 10:55:36 +0200 Subject: [PATCH 100/171] Update tree-sitter-ruby --- ruby/Cargo.lock | Bin 15116 -> 15116 bytes ruby/extractor/Cargo.toml | 2 +- ruby/generator/Cargo.toml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby/Cargo.lock b/ruby/Cargo.lock index dafdc4137e110de9d85e05a538e9500f950a6126..75db597d564cb83e29377d0002720a98508a3f0c 100644 GIT binary patch delta 101 zcmeAv>nYn{Y8H@aY-wzkXl!a?nrx7iVrgt*l4y{WW@%xZmY9}oo@!`rVq%nYn{Y8H^1l$MfYWMN@pVw94YYMN+iWNe&jWNKiUXlQI|X<}($WSo*>VWezG Uq{7LGYNC_pn(AymX6D8M0QPMiJpcdz diff --git a/ruby/extractor/Cargo.toml b/ruby/extractor/Cargo.toml index aa3d7de36cf..56afbacc031 100644 --- a/ruby/extractor/Cargo.toml +++ b/ruby/extractor/Cargo.toml @@ -11,7 +11,7 @@ flate2 = "1.0" node-types = { path = "../node-types" } tree-sitter = "0.19" tree-sitter-embedded-template = "0.19" -tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "1ebfdb288842dae5a9233e2509a135949023dd82" } +tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "1a3936a3545c0bd9344a0bf983fafc7e17443e39" } clap = "3.0" tracing = "0.1" tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } diff --git a/ruby/generator/Cargo.toml b/ruby/generator/Cargo.toml index ff67ec7df64..4f7824e22ea 100644 --- a/ruby/generator/Cargo.toml +++ b/ruby/generator/Cargo.toml @@ -12,4 +12,4 @@ node-types = { path = "../node-types" } tracing = "0.1" tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } tree-sitter-embedded-template = "0.19" -tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "1ebfdb288842dae5a9233e2509a135949023dd82" } +tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "1a3936a3545c0bd9344a0bf983fafc7e17443e39" } From a848929069e1d07714e2bd346d6187c1ff90e15c Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Tue, 26 Apr 2022 10:57:26 +0200 Subject: [PATCH 101/171] Regenerate QLL library --- .../codeql/ruby/ast/internal/TreeSitter.qll | 35 ++++-- ruby/ql/lib/ruby.dbscheme | 110 +++++++++++------- 2 files changed, 93 insertions(+), 52 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll index 6151dcf67a8..51f18440a0b 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll @@ -50,6 +50,8 @@ module Ruby { class UnderscoreArg extends @ruby_underscore_arg, AstNode { } + class UnderscoreCallOperator extends @ruby_underscore_call_operator, AstNode { } + class UnderscoreExpression extends @ruby_underscore_expression, AstNode { } class UnderscoreLhs extends @ruby_underscore_lhs, AstNode { } @@ -238,7 +240,7 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Binary" } /** Gets the node corresponding to the field `left`. */ - final UnderscoreExpression getLeft() { ruby_binary_def(this, result, _, _) } + final AstNode getLeft() { ruby_binary_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ final string getOperator() { @@ -350,11 +352,16 @@ module Ruby { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockParameters" } + /** Gets the node corresponding to the field `locals`. */ + final Identifier getLocals(int i) { ruby_block_parameters_locals(this, i, result) } + /** Gets the `i`th child of this node. */ final AstNode getChild(int i) { ruby_block_parameters_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_block_parameters_child(this, _, result) } + final override AstNode getAFieldOrChild() { + ruby_block_parameters_locals(this, _, result) or ruby_block_parameters_child(this, _, result) + } } /** A class representing `break` nodes. */ @@ -381,16 +388,20 @@ module Ruby { final AstNode getBlock() { ruby_call_block(this, result) } /** Gets the node corresponding to the field `method`. */ - final AstNode getMethod() { ruby_call_def(this, result) } + final AstNode getMethod() { ruby_call_method(this, result) } + + /** Gets the node corresponding to the field `operator`. */ + final UnderscoreCallOperator getOperator() { ruby_call_operator(this, result) } /** Gets the node corresponding to the field `receiver`. */ - final AstNode getReceiver() { ruby_call_receiver(this, result) } + final UnderscorePrimary getReceiver() { ruby_call_receiver(this, result) } /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { ruby_call_arguments(this, result) or ruby_call_block(this, result) or - ruby_call_def(this, result) or + ruby_call_method(this, result) or + ruby_call_operator(this, result) or ruby_call_receiver(this, result) } } @@ -486,10 +497,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Comment" } } - /** A class representing `complex` tokens. */ - class Complex extends @ruby_token_complex, Token { + /** A class representing `complex` nodes. */ + class Complex extends @ruby_complex, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Complex" } + + /** Gets the child of this node. */ + final AstNode getChild() { ruby_complex_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { ruby_complex_def(this, result) } } /** A class representing `conditional` nodes. */ @@ -1199,7 +1216,7 @@ module Ruby { } /** Gets the node corresponding to the field `right`. */ - final UnderscoreExpression getRight() { ruby_operator_assignment_def(this, _, _, result) } + final AstNode getRight() { ruby_operator_assignment_def(this, _, _, result) } /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { @@ -1447,7 +1464,7 @@ module Ruby { final override string getAPrimaryQlClass() { result = "ScopeResolution" } /** Gets the node corresponding to the field `name`. */ - final AstNode getName() { ruby_scope_resolution_def(this, result) } + final Constant getName() { ruby_scope_resolution_def(this, result) } /** Gets the node corresponding to the field `scope`. */ final AstNode getScope() { ruby_scope_resolution_scope(this, result) } diff --git a/ruby/ql/lib/ruby.dbscheme b/ruby/ql/lib/ruby.dbscheme index 9fdd1d40fd3..1199e154f5e 100644 --- a/ruby/ql/lib/ruby.dbscheme +++ b/ruby/ql/lib/ruby.dbscheme @@ -52,6 +52,8 @@ case @diagnostic.severity of @ruby_underscore_arg = @ruby_assignment | @ruby_binary | @ruby_conditional | @ruby_operator_assignment | @ruby_range | @ruby_unary | @ruby_underscore_primary +@ruby_underscore_call_operator = @ruby_reserved_word + @ruby_underscore_expression = @ruby_assignment | @ruby_binary | @ruby_break | @ruby_call | @ruby_next | @ruby_operator_assignment | @ruby_return | @ruby_unary | @ruby_underscore_arg | @ruby_yield @ruby_underscore_lhs = @ruby_call | @ruby_element_reference | @ruby_scope_resolution | @ruby_token_false | @ruby_token_nil | @ruby_token_true | @ruby_underscore_variable @@ -66,13 +68,13 @@ case @diagnostic.severity of @ruby_underscore_pattern_expr_basic = @ruby_array_pattern | @ruby_expression_reference_pattern | @ruby_find_pattern | @ruby_hash_pattern | @ruby_parenthesized_pattern | @ruby_range | @ruby_token_identifier | @ruby_underscore_pattern_constant | @ruby_underscore_pattern_primitive | @ruby_variable_reference_pattern -@ruby_underscore_pattern_primitive = @ruby_delimited_symbol | @ruby_lambda | @ruby_regex | @ruby_string__ | @ruby_string_array | @ruby_symbol_array | @ruby_token_encoding | @ruby_token_false | @ruby_token_file | @ruby_token_line | @ruby_token_nil | @ruby_token_self | @ruby_token_simple_symbol | @ruby_token_true | @ruby_unary | @ruby_underscore_simple_numeric +@ruby_underscore_pattern_primitive = @ruby_delimited_symbol | @ruby_lambda | @ruby_regex | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_symbol_array | @ruby_token_encoding | @ruby_token_false | @ruby_token_file | @ruby_token_heredoc_beginning | @ruby_token_line | @ruby_token_nil | @ruby_token_self | @ruby_token_simple_symbol | @ruby_token_true | @ruby_unary | @ruby_underscore_simple_numeric @ruby_underscore_pattern_top_expr_body = @ruby_array_pattern | @ruby_find_pattern | @ruby_hash_pattern | @ruby_underscore_pattern_expr -@ruby_underscore_primary = @ruby_array | @ruby_begin | @ruby_break | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_delimited_symbol | @ruby_for | @ruby_hash | @ruby_if | @ruby_lambda | @ruby_method | @ruby_module | @ruby_next | @ruby_parenthesized_statements | @ruby_redo | @ruby_regex | @ruby_retry | @ruby_return | @ruby_singleton_class | @ruby_singleton_method | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_symbol_array | @ruby_token_character | @ruby_token_heredoc_beginning | @ruby_token_simple_symbol | @ruby_unary | @ruby_underscore_lhs | @ruby_underscore_simple_numeric | @ruby_unless | @ruby_until | @ruby_while | @ruby_yield +@ruby_underscore_primary = @ruby_array | @ruby_begin | @ruby_break | @ruby_call | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_delimited_symbol | @ruby_for | @ruby_hash | @ruby_if | @ruby_lambda | @ruby_method | @ruby_module | @ruby_next | @ruby_parenthesized_statements | @ruby_redo | @ruby_regex | @ruby_retry | @ruby_return | @ruby_singleton_class | @ruby_singleton_method | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_symbol_array | @ruby_token_character | @ruby_token_heredoc_beginning | @ruby_token_simple_symbol | @ruby_unary | @ruby_underscore_lhs | @ruby_underscore_simple_numeric | @ruby_unless | @ruby_until | @ruby_while | @ruby_yield -@ruby_underscore_simple_numeric = @ruby_rational | @ruby_token_complex | @ruby_token_float | @ruby_token_integer +@ruby_underscore_simple_numeric = @ruby_complex | @ruby_rational | @ruby_token_float | @ruby_token_integer @ruby_underscore_statement = @ruby_alias | @ruby_begin_block | @ruby_end_block | @ruby_if_modifier | @ruby_rescue_modifier | @ruby_undef | @ruby_underscore_expression | @ruby_unless_modifier | @ruby_until_modifier | @ruby_while_modifier @@ -147,7 +149,7 @@ ruby_as_pattern_def( @ruby_assignment_left_type = @ruby_left_assignment_list | @ruby_underscore_lhs -@ruby_assignment_right_type = @ruby_right_assignment_list | @ruby_splat_argument | @ruby_underscore_expression +@ruby_assignment_right_type = @ruby_rescue_modifier | @ruby_right_assignment_list | @ruby_splat_argument | @ruby_underscore_expression ruby_assignment_def( unique int id: @ruby_assignment, @@ -207,6 +209,8 @@ ruby_begin_block_def( unique int id: @ruby_begin_block ); +@ruby_binary_left_type = @ruby_underscore_expression | @ruby_underscore_simple_numeric + case @ruby_binary.operator of 0 = @ruby_binary_bangequal | 1 = @ruby_binary_bangtilde @@ -238,7 +242,7 @@ case @ruby_binary.operator of ruby_binary_def( unique int id: @ruby_binary, - int left: @ruby_underscore_expression ref, + int left: @ruby_binary_left_type ref, int operator: int ref, int right: @ruby_underscore_expression ref ); @@ -279,6 +283,13 @@ ruby_block_parameter_def( unique int id: @ruby_block_parameter ); +#keyset[ruby_block_parameters, index] +ruby_block_parameters_locals( + int ruby_block_parameters: @ruby_block_parameters ref, + int index: int ref, + unique int locals: @ruby_token_identifier ref +); + @ruby_block_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier #keyset[ruby_block_parameters, index] @@ -313,18 +324,25 @@ ruby_call_block( unique int block: @ruby_call_block_type ref ); -@ruby_call_method_type = @ruby_argument_list | @ruby_scope_resolution | @ruby_token_operator | @ruby_underscore_variable +@ruby_call_method_type = @ruby_token_operator | @ruby_underscore_variable -@ruby_call_receiver_type = @ruby_call | @ruby_underscore_primary +ruby_call_method( + unique int ruby_call: @ruby_call ref, + unique int method: @ruby_call_method_type ref +); + +ruby_call_operator( + unique int ruby_call: @ruby_call ref, + unique int operator: @ruby_underscore_call_operator ref +); ruby_call_receiver( unique int ruby_call: @ruby_call ref, - unique int receiver: @ruby_call_receiver_type ref + unique int receiver: @ruby_underscore_primary ref ); ruby_call_def( - unique int id: @ruby_call, - int method: @ruby_call_method_type ref + unique int id: @ruby_call ); ruby_case_value( @@ -394,6 +412,13 @@ ruby_class_def( int name: @ruby_class_name_type ref ); +@ruby_complex_child_type = @ruby_rational | @ruby_token_float | @ruby_token_integer + +ruby_complex_def( + unique int id: @ruby_complex, + int child: @ruby_complex_child_type ref +); + ruby_conditional_def( unique int id: @ruby_conditional, int alternative: @ruby_underscore_arg ref, @@ -846,11 +871,13 @@ case @ruby_operator_assignment.operator of ; +@ruby_operator_assignment_right_type = @ruby_rescue_modifier | @ruby_underscore_expression + ruby_operator_assignment_def( unique int id: @ruby_operator_assignment, int left: @ruby_underscore_lhs ref, int operator: int ref, - int right: @ruby_underscore_expression ref + int right: @ruby_operator_assignment_right_type ref ); ruby_optional_parameter_def( @@ -1030,8 +1057,6 @@ ruby_right_assignment_list_def( unique int id: @ruby_right_assignment_list ); -@ruby_scope_resolution_name_type = @ruby_token_constant | @ruby_token_identifier - @ruby_scope_resolution_scope_type = @ruby_underscore_pattern_constant | @ruby_underscore_primary ruby_scope_resolution_scope( @@ -1041,7 +1066,7 @@ ruby_scope_resolution_scope( ruby_scope_resolution_def( unique int id: @ruby_scope_resolution, - int name: @ruby_scope_resolution_name_type ref + int name: @ruby_token_constant ref ); ruby_setter_def( @@ -1289,38 +1314,37 @@ case @ruby_token.kind of | 1 = @ruby_token_character | 2 = @ruby_token_class_variable | 3 = @ruby_token_comment -| 4 = @ruby_token_complex -| 5 = @ruby_token_constant -| 6 = @ruby_token_empty_statement -| 7 = @ruby_token_encoding -| 8 = @ruby_token_escape_sequence -| 9 = @ruby_token_false -| 10 = @ruby_token_file -| 11 = @ruby_token_float -| 12 = @ruby_token_forward_argument -| 13 = @ruby_token_forward_parameter -| 14 = @ruby_token_global_variable -| 15 = @ruby_token_hash_key_symbol -| 16 = @ruby_token_hash_splat_nil -| 17 = @ruby_token_heredoc_beginning -| 18 = @ruby_token_heredoc_content -| 19 = @ruby_token_heredoc_end -| 20 = @ruby_token_identifier -| 21 = @ruby_token_instance_variable -| 22 = @ruby_token_integer -| 23 = @ruby_token_line -| 24 = @ruby_token_nil -| 25 = @ruby_token_operator -| 26 = @ruby_token_self -| 27 = @ruby_token_simple_symbol -| 28 = @ruby_token_string_content -| 29 = @ruby_token_super -| 30 = @ruby_token_true -| 31 = @ruby_token_uninterpreted +| 4 = @ruby_token_constant +| 5 = @ruby_token_empty_statement +| 6 = @ruby_token_encoding +| 7 = @ruby_token_escape_sequence +| 8 = @ruby_token_false +| 9 = @ruby_token_file +| 10 = @ruby_token_float +| 11 = @ruby_token_forward_argument +| 12 = @ruby_token_forward_parameter +| 13 = @ruby_token_global_variable +| 14 = @ruby_token_hash_key_symbol +| 15 = @ruby_token_hash_splat_nil +| 16 = @ruby_token_heredoc_beginning +| 17 = @ruby_token_heredoc_content +| 18 = @ruby_token_heredoc_end +| 19 = @ruby_token_identifier +| 20 = @ruby_token_instance_variable +| 21 = @ruby_token_integer +| 22 = @ruby_token_line +| 23 = @ruby_token_nil +| 24 = @ruby_token_operator +| 25 = @ruby_token_self +| 26 = @ruby_token_simple_symbol +| 27 = @ruby_token_string_content +| 28 = @ruby_token_super +| 29 = @ruby_token_true +| 30 = @ruby_token_uninterpreted ; -@ruby_ast_node = @ruby_alias | @ruby_alternative_pattern | @ruby_argument_list | @ruby_array | @ruby_array_pattern | @ruby_as_pattern | @ruby_assignment | @ruby_bare_string | @ruby_bare_symbol | @ruby_begin | @ruby_begin_block | @ruby_binary | @ruby_block | @ruby_block_argument | @ruby_block_parameter | @ruby_block_parameters | @ruby_break | @ruby_call | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_conditional | @ruby_delimited_symbol | @ruby_destructured_left_assignment | @ruby_destructured_parameter | @ruby_do | @ruby_do_block | @ruby_element_reference | @ruby_else | @ruby_elsif | @ruby_end_block | @ruby_ensure | @ruby_exception_variable | @ruby_exceptions | @ruby_expression_reference_pattern | @ruby_find_pattern | @ruby_for | @ruby_hash | @ruby_hash_pattern | @ruby_hash_splat_argument | @ruby_hash_splat_parameter | @ruby_heredoc_body | @ruby_if | @ruby_if_guard | @ruby_if_modifier | @ruby_in | @ruby_in_clause | @ruby_interpolation | @ruby_keyword_parameter | @ruby_keyword_pattern | @ruby_lambda | @ruby_lambda_parameters | @ruby_left_assignment_list | @ruby_method | @ruby_method_parameters | @ruby_module | @ruby_next | @ruby_operator_assignment | @ruby_optional_parameter | @ruby_pair | @ruby_parenthesized_pattern | @ruby_parenthesized_statements | @ruby_pattern | @ruby_program | @ruby_range | @ruby_rational | @ruby_redo | @ruby_regex | @ruby_rescue | @ruby_rescue_modifier | @ruby_rest_assignment | @ruby_retry | @ruby_return | @ruby_right_assignment_list | @ruby_scope_resolution | @ruby_setter | @ruby_singleton_class | @ruby_singleton_method | @ruby_splat_argument | @ruby_splat_parameter | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_superclass | @ruby_symbol_array | @ruby_then | @ruby_token | @ruby_unary | @ruby_undef | @ruby_unless | @ruby_unless_guard | @ruby_unless_modifier | @ruby_until | @ruby_until_modifier | @ruby_variable_reference_pattern | @ruby_when | @ruby_while | @ruby_while_modifier | @ruby_yield +@ruby_ast_node = @ruby_alias | @ruby_alternative_pattern | @ruby_argument_list | @ruby_array | @ruby_array_pattern | @ruby_as_pattern | @ruby_assignment | @ruby_bare_string | @ruby_bare_symbol | @ruby_begin | @ruby_begin_block | @ruby_binary | @ruby_block | @ruby_block_argument | @ruby_block_parameter | @ruby_block_parameters | @ruby_break | @ruby_call | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_complex | @ruby_conditional | @ruby_delimited_symbol | @ruby_destructured_left_assignment | @ruby_destructured_parameter | @ruby_do | @ruby_do_block | @ruby_element_reference | @ruby_else | @ruby_elsif | @ruby_end_block | @ruby_ensure | @ruby_exception_variable | @ruby_exceptions | @ruby_expression_reference_pattern | @ruby_find_pattern | @ruby_for | @ruby_hash | @ruby_hash_pattern | @ruby_hash_splat_argument | @ruby_hash_splat_parameter | @ruby_heredoc_body | @ruby_if | @ruby_if_guard | @ruby_if_modifier | @ruby_in | @ruby_in_clause | @ruby_interpolation | @ruby_keyword_parameter | @ruby_keyword_pattern | @ruby_lambda | @ruby_lambda_parameters | @ruby_left_assignment_list | @ruby_method | @ruby_method_parameters | @ruby_module | @ruby_next | @ruby_operator_assignment | @ruby_optional_parameter | @ruby_pair | @ruby_parenthesized_pattern | @ruby_parenthesized_statements | @ruby_pattern | @ruby_program | @ruby_range | @ruby_rational | @ruby_redo | @ruby_regex | @ruby_rescue | @ruby_rescue_modifier | @ruby_rest_assignment | @ruby_retry | @ruby_return | @ruby_right_assignment_list | @ruby_scope_resolution | @ruby_setter | @ruby_singleton_class | @ruby_singleton_method | @ruby_splat_argument | @ruby_splat_parameter | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_superclass | @ruby_symbol_array | @ruby_then | @ruby_token | @ruby_unary | @ruby_undef | @ruby_unless | @ruby_unless_guard | @ruby_unless_modifier | @ruby_until | @ruby_until_modifier | @ruby_variable_reference_pattern | @ruby_when | @ruby_while | @ruby_while_modifier | @ruby_yield @ruby_ast_node_parent = @file | @ruby_ast_node From 65989ae564a82d73e269e7c16b33d4ba9bc90a1b Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Wed, 27 Apr 2022 21:27:45 +0200 Subject: [PATCH 102/171] Update dbscheme stats --- ruby/ql/lib/ruby.dbscheme.stats | 6547 ++++++++++++++++--------------- 1 file changed, 3332 insertions(+), 3215 deletions(-) diff --git a/ruby/ql/lib/ruby.dbscheme.stats b/ruby/ql/lib/ruby.dbscheme.stats index 4ee465bdb28..782ae4db56b 100644 --- a/ruby/ql/lib/ruby.dbscheme.stats +++ b/ruby/ql/lib/ruby.dbscheme.stats @@ -5,7 +5,7 @@ @diagnostic_error - 129 + 155 @diagnostic_info @@ -21,7 +21,7 @@ @erb_directive - 1449 + 1414 @erb_graphql_directive @@ -29,19 +29,19 @@ @erb_output_directive - 3895 + 3806 @erb_reserved_word - 10689 + 10441 @erb_template - 1562 + 1563 @erb_token_code - 5344 + 5220 @erb_token_comment @@ -49,23 +49,23 @@ @erb_token_content - 3816 + 3761 @file - 16948 + 17168 @folder - 4774 + 4792 @location_default - 8504708 + 8508604 - + @ruby_alias - 1256 + 1244 @ruby_alternative_pattern @@ -73,11 +73,11 @@ @ruby_argument_list - 663118 + 664517 @ruby_array - 245466 + 245561 @ruby_array_pattern @@ -89,19 +89,19 @@ @ruby_assignment - 130604 + 130246 @ruby_bare_string - 11474 + 11487 @ruby_bare_symbol - 2137 + 2106 @ruby_begin - 2533 + 2523 @ruby_begin_block @@ -113,19 +113,19 @@ @ruby_binary_ampersandampersand - 8822 + 8700 @ruby_binary_and - 1355 + 1348 @ruby_binary_bangequal - 1585 + 1586 @ruby_binary_bangtilde - 177 + 178 @ruby_binary_caret @@ -133,7 +133,7 @@ @ruby_binary_equalequal - 31084 + 31159 @ruby_binary_equalequalequal @@ -141,15 +141,15 @@ @ruby_binary_equaltilde - 1822 + 1820 @ruby_binary_langle - 1343 + 1334 @ruby_binary_langleequal - 369 + 368 @ruby_binary_langleequalrangle @@ -157,43 +157,43 @@ @ruby_binary_langlelangle - 10484 + 10368 @ruby_binary_minus - 2883 + 2381 @ruby_binary_or - 673 + 665 @ruby_binary_percent - 1014 + 1009 @ruby_binary_pipe - 981 + 968 @ruby_binary_pipepipe - 8088 + 8001 @ruby_binary_plus - 6102 + 6116 @ruby_binary_rangle - 2431 + 2400 @ruby_binary_rangleequal - 556 + 558 @ruby_binary_ranglerangle - 230 + 231 @ruby_binary_slash @@ -201,19 +201,19 @@ @ruby_binary_star - 3119 + 3286 @ruby_binary_starstar - 1291 + 1316 @ruby_block - 96904 + 97359 @ruby_block_argument - 6048 + 6050 @ruby_block_parameter @@ -221,15 +221,15 @@ @ruby_block_parameters - 23501 + 23336 @ruby_break - 3343 + 3338 @ruby_call - 961220 + 965401 @ruby_case__ @@ -237,23 +237,27 @@ @ruby_case_match - 2 + 0 @ruby_chained_string - 894 + 885 @ruby_class - 16778 + 16841 + + + @ruby_complex + 53 @ruby_conditional - 3556 + 3464 @ruby_delimited_symbol - 1216 + 1257 @ruby_destructured_left_assignment @@ -265,23 +269,23 @@ @ruby_do - 1621 + 1610 @ruby_do_block - 136559 + 137435 @ruby_element_reference - 82281 + 82234 @ruby_else - 6946 + 6933 @ruby_elsif - 1606 + 1595 @ruby_end_block @@ -289,15 +293,15 @@ @ruby_ensure - 3786 + 3718 @ruby_exception_variable - 1021 + 1001 @ruby_exceptions - 1641 + 1639 @ruby_expression_reference_pattern @@ -309,11 +313,11 @@ @ruby_for - 163 + 162 @ruby_hash - 39344 + 39413 @ruby_hash_pattern @@ -321,19 +325,19 @@ @ruby_hash_splat_argument - 1813 + 1856 @ruby_hash_splat_parameter - 1351 + 1355 @ruby_heredoc_body - 5577 + 5575 @ruby_if - 18504 + 18392 @ruby_if_guard @@ -341,23 +345,23 @@ @ruby_if_modifier - 13763 + 13620 @ruby_in - 163 + 162 @ruby_in_clause - 2 + 0 @ruby_interpolation - 38383 + 38208 @ruby_keyword_parameter - 3777 + 3794 @ruby_keyword_pattern @@ -365,39 +369,39 @@ @ruby_lambda - 7499 + 7472 @ruby_lambda_parameters - 1659 + 1664 @ruby_left_assignment_list - 2887 + 2873 @ruby_method - 98643 + 98356 @ruby_method_parameters - 28992 + 28861 @ruby_module - 21140 + 21557 @ruby_next - 2070 + 2005 @ruby_operator_assignment_ampersandampersandequal - 90 + 88 @ruby_operator_assignment_ampersandequal - 15 + 16 @ruby_operator_assignment_caretequal @@ -409,7 +413,7 @@ @ruby_operator_assignment_minusequal - 294 + 292 @ruby_operator_assignment_percentequal @@ -421,11 +425,11 @@ @ruby_operator_assignment_pipepipeequal - 4638 + 4611 @ruby_operator_assignment_plusequal - 1752 + 1759 @ruby_operator_assignment_ranglerangleequal @@ -445,11 +449,11 @@ @ruby_optional_parameter - 6527 + 6435 @ruby_pair - 235172 + 235158 @ruby_parenthesized_pattern @@ -457,23 +461,23 @@ @ruby_parenthesized_statements - 10153 + 10247 @ruby_pattern - 3878 + 3895 @ruby_program - 16935 + 17142 @ruby_range_dotdot - 2750 + 2831 @ruby_range_dotdotdot - 1544 + 1356 @ruby_rational @@ -485,19 +489,19 @@ @ruby_regex - 12828 + 12854 @ruby_rescue - 2085 + 2061 @ruby_rescue_modifier - 551 + 525 @ruby_reserved_word - 3653831 + 3667249 @ruby_rest_assignment @@ -509,15 +513,15 @@ @ruby_return - 8521 + 8495 @ruby_right_assignment_list - 1376 + 1288 @ruby_scope_resolution - 80201 + 80009 @ruby_setter @@ -525,63 +529,59 @@ @ruby_singleton_class - 626 + 620 @ruby_singleton_method - 6563 + 6539 @ruby_splat_argument - 3179 + 3046 @ruby_splat_parameter - 2936 + 2905 @ruby_string__ - 474637 + 473533 @ruby_string_array - 3868 + 3840 @ruby_subshell - 409 + 403 @ruby_superclass - 13262 + 13318 @ruby_symbol_array - 457 + 463 @ruby_then - 24592 + 24329 @ruby_token_character - 416 + 437 @ruby_token_class_variable - 776 + 857 @ruby_token_comment - 179885 - - - @ruby_token_complex - 36 + 180978 @ruby_token_constant - 284770 + 283898 @ruby_token_empty_statement @@ -593,11 +593,11 @@ @ruby_token_escape_sequence - 75435 + 75715 @ruby_token_false - 16937 + 16909 @ruby_token_file @@ -605,23 +605,23 @@ @ruby_token_float - 7814 + 7830 @ruby_token_forward_argument - 66 + 72 @ruby_token_forward_parameter - 75 + 94 @ruby_token_global_variable - 7078 + 7057 @ruby_token_hash_key_symbol - 228521 + 228509 @ruby_token_hash_splat_nil @@ -629,27 +629,27 @@ @ruby_token_heredoc_beginning - 5603 + 5600 @ruby_token_heredoc_content - 12423 + 12542 @ruby_token_heredoc_end - 5577 + 5575 @ruby_token_identifier - 1482144 + 1483080 @ruby_token_instance_variable - 81594 + 81049 @ruby_token_integer - 298439 + 298658 @ruby_token_line @@ -657,31 +657,31 @@ @ruby_token_nil - 17874 + 17920 @ruby_token_operator - 782 + 781 @ruby_token_self - 13136 + 12958 @ruby_token_simple_symbol - 249753 + 249119 @ruby_token_string_content - 488998 + 488016 @ruby_token_super - 5009 + 5058 @ruby_token_true - 23064 + 23298 @ruby_token_uninterpreted @@ -689,23 +689,23 @@ @ruby_unary_bang - 5738 + 5788 @ruby_unary_definedquestion - 1311 + 1312 @ruby_unary_minus - 8570 + 9122 @ruby_unary_not - 237 + 236 @ruby_unary_plus - 1389 + 1386 @ruby_unary_tilde @@ -717,7 +717,7 @@ @ruby_unless - 2568 + 2578 @ruby_unless_guard @@ -725,15 +725,15 @@ @ruby_unless_modifier - 4341 + 4207 @ruby_until - 114 + 113 @ruby_until_modifier - 218 + 206 @ruby_variable_reference_pattern @@ -741,32 +741,32 @@ @ruby_when - 3229 + 3239 @ruby_while - 1344 + 1335 @ruby_while_modifier - 184 + 179 @ruby_yield - 2406 + 2385 containerparent - 21696 + 21934 parent - 4774 + 4792 child - 21696 + 21934 @@ -780,37 +780,37 @@ 1 2 - 2134 + 2142 2 3 - 905 + 909 3 4 - 439 + 441 4 5 - 297 + 298 5 7 - 375 + 376 7 13 - 388 + 389 13 - 120 - 232 + 124 + 233 @@ -826,7 +826,7 @@ 1 2 - 21696 + 21934 @@ -836,11 +836,11 @@ diagnostics - 129 + 155 id - 129 + 155 severity @@ -856,11 +856,11 @@ full_error_message - 103 + 129 location - 129 + 155 @@ -874,7 +874,7 @@ 1 2 - 129 + 155 @@ -890,7 +890,7 @@ 1 2 - 129 + 155 @@ -906,7 +906,7 @@ 1 2 - 129 + 155 @@ -922,7 +922,7 @@ 1 2 - 129 + 155 @@ -938,7 +938,7 @@ 1 2 - 129 + 155 @@ -952,8 +952,8 @@ 12 - 10 - 11 + 12 + 13 12 @@ -1000,8 +1000,8 @@ 12 - 8 - 9 + 10 + 11 12 @@ -1016,8 +1016,8 @@ 12 - 10 - 11 + 12 + 13 12 @@ -1032,8 +1032,8 @@ 12 - 10 - 11 + 12 + 13 12 @@ -1080,8 +1080,8 @@ 12 - 8 - 9 + 10 + 11 12 @@ -1096,8 +1096,8 @@ 12 - 10 - 11 + 12 + 13 12 @@ -1107,6 +1107,59 @@ error_message id + + + 12 + + + 1 + 2 + 12 + + + 11 + 12 + 12 + + + + + + + error_message + severity + + + 12 + + + 1 + 2 + 25 + + + + + + + error_message + error_tag + + + 12 + + + 1 + 2 + 25 + + + + + + + error_message + full_error_message 12 @@ -1125,59 +1178,6 @@ - - error_message - severity - - - 12 - - - 1 - 2 - 25 - - - - - - - error_message - error_tag - - - 12 - - - 1 - 2 - 25 - - - - - - - error_message - full_error_message - - - 12 - - - 1 - 2 - 12 - - - 7 - 8 - 12 - - - - - error_message location @@ -1191,8 +1191,8 @@ 12 - 9 - 10 + 11 + 12 12 @@ -1209,7 +1209,7 @@ 1 2 - 77 + 103 2 @@ -1230,7 +1230,7 @@ 1 2 - 103 + 129 @@ -1246,7 +1246,7 @@ 1 2 - 103 + 129 @@ -1262,7 +1262,7 @@ 1 2 - 103 + 129 @@ -1278,7 +1278,7 @@ 1 2 - 77 + 103 2 @@ -1299,7 +1299,7 @@ 1 2 - 129 + 155 @@ -1315,7 +1315,7 @@ 1 2 - 129 + 155 @@ -1331,7 +1331,7 @@ 1 2 - 129 + 155 @@ -1347,7 +1347,7 @@ 1 2 - 129 + 155 @@ -1363,7 +1363,7 @@ 1 2 - 129 + 155 @@ -1373,23 +1373,23 @@ erb_ast_node_info - 25623 + 25078 node - 25623 + 25078 parent - 6199 + 6088 parent_index - 754 + 668 loc - 25620 + 25075 @@ -1403,7 +1403,7 @@ 1 2 - 25623 + 25078 @@ -1419,7 +1419,7 @@ 1 2 - 25623 + 25078 @@ -1435,7 +1435,7 @@ 1 2 - 25623 + 25078 @@ -1451,17 +1451,17 @@ 1 3 - 454 + 460 3 4 - 5487 + 5360 4 - 250 - 257 + 226 + 267 @@ -1477,17 +1477,17 @@ 1 3 - 454 + 460 3 4 - 5487 + 5360 4 - 250 - 257 + 226 + 267 @@ -1503,17 +1503,17 @@ 1 3 - 454 + 460 3 4 - 5487 + 5360 4 - 250 - 257 + 226 + 267 @@ -1529,52 +1529,57 @@ 1 2 - 160 + 86 2 3 - 115 + 106 3 4 - 97 + 121 4 5 - 21 + 5 5 6 - 72 + 65 6 - 8 - 60 + 7 + 50 - 8 - 13 - 60 + 7 + 11 + 50 - 14 - 24 - 60 + 11 + 19 + 53 - 24 - 45 - 57 + 19 + 38 + 53 - 48 - 2046 - 48 + 39 + 72 + 50 + + + 74 + 2050 + 23 @@ -1590,52 +1595,57 @@ 1 2 - 160 + 86 2 3 - 115 + 106 3 4 - 97 + 121 4 5 - 21 + 5 5 6 - 72 + 65 6 - 8 - 60 + 7 + 50 - 8 - 13 - 60 + 7 + 11 + 50 - 14 - 24 - 60 + 11 + 19 + 53 - 24 - 45 - 57 + 19 + 38 + 53 - 48 - 2046 - 48 + 39 + 72 + 50 + + + 74 + 2050 + 23 @@ -1651,52 +1661,57 @@ 1 2 - 160 + 86 2 3 - 115 + 106 3 4 - 97 + 121 4 5 - 21 + 5 5 6 - 72 + 65 6 - 8 - 60 + 7 + 50 - 8 - 13 - 60 + 7 + 11 + 50 - 14 - 24 - 60 + 11 + 19 + 53 - 24 - 45 - 57 + 19 + 38 + 53 - 48 - 2045 - 48 + 39 + 72 + 50 + + + 74 + 2049 + 23 @@ -1712,12 +1727,12 @@ 1 2 - 25617 + 25072 2 3 - 3 + 2 @@ -1733,12 +1748,12 @@ 1 2 - 25617 + 25072 2 3 - 3 + 2 @@ -1754,7 +1769,7 @@ 1 2 - 25620 + 25075 @@ -1812,15 +1827,15 @@ erb_directive_def - 1449 + 1414 id - 1449 + 1414 child - 1449 + 1414 @@ -1834,7 +1849,7 @@ 1 2 - 1449 + 1414 @@ -1850,7 +1865,7 @@ 1 2 - 1449 + 1414 @@ -1882,7 +1897,7 @@ 1 2 - 3 + 2 @@ -1902,15 +1917,15 @@ erb_output_directive_def - 3895 + 3806 id - 3895 + 3806 child - 3895 + 3806 @@ -1924,7 +1939,7 @@ 1 2 - 3895 + 3806 @@ -1940,7 +1955,7 @@ 1 2 - 3895 + 3806 @@ -1950,19 +1965,19 @@ erb_template_child - 9161 + 8982 erb_template - 427 + 433 index - 754 + 668 child - 9161 + 8982 @@ -1976,52 +1991,52 @@ 1 3 - 27 + 26 3 4 - 142 + 139 4 7 - 24 + 26 7 9 - 30 + 29 9 - 13 - 36 + 12 + 35 - 13 + 12 17 - 33 + 38 17 - 30 - 36 + 29 + 32 - 30 - 43 - 36 + 29 + 35 + 35 - 43 - 72 - 33 + 35 + 56 + 35 - 74 - 250 - 27 + 61 + 226 + 32 @@ -2037,52 +2052,52 @@ 1 3 - 27 + 26 3 4 - 142 + 139 4 7 - 24 + 26 7 9 - 30 + 29 9 - 13 - 36 + 12 + 35 - 13 + 12 17 - 33 + 38 17 - 30 - 36 + 29 + 32 - 30 - 43 - 36 + 29 + 35 + 35 - 43 - 72 - 33 + 35 + 56 + 35 - 74 - 250 - 27 + 61 + 226 + 32 @@ -2098,52 +2113,57 @@ 1 2 - 160 + 86 2 3 - 115 + 106 3 4 - 97 + 121 4 5 - 21 + 5 5 6 - 72 + 65 6 - 8 - 60 + 7 + 50 - 8 - 13 - 60 + 7 + 11 + 50 - 14 - 24 - 60 + 11 + 19 + 53 - 24 - 45 - 57 + 19 + 38 + 53 - 48 - 142 - 48 + 39 + 72 + 50 + + + 74 + 147 + 23 @@ -2159,52 +2179,57 @@ 1 2 - 160 + 86 2 3 - 115 + 106 3 4 - 97 + 121 4 5 - 21 + 5 5 6 - 72 + 65 6 - 8 - 60 + 7 + 50 - 8 - 13 - 60 + 7 + 11 + 50 - 14 - 24 - 60 + 11 + 19 + 53 - 24 - 45 - 57 + 19 + 38 + 53 - 48 - 142 - 48 + 39 + 72 + 50 + + + 74 + 147 + 23 @@ -2220,7 +2245,7 @@ 1 2 - 9161 + 8982 @@ -2236,7 +2261,7 @@ 1 2 - 9161 + 8982 @@ -2246,30 +2271,30 @@ erb_template_def - 1562 + 1563 id - 1562 + 1563 erb_tokeninfo - 19851 + 19423 id - 19851 + 19423 kind - 9 + 8 value - 5875 + 5800 @@ -2283,7 +2308,7 @@ 1 2 - 19851 + 19423 @@ -2299,7 +2324,7 @@ 1 2 - 19851 + 19423 @@ -2313,19 +2338,19 @@ 12 - 1259 - 1260 - 3 + 1266 + 1267 + 2 - 1763 - 1764 - 3 + 1757 + 1758 + 2 - 3526 - 3527 - 3 + 3514 + 3515 + 2 @@ -2341,17 +2366,17 @@ 52 53 - 3 + 2 - 873 - 874 - 3 + 884 + 885 + 2 - 1013 - 1014 - 3 + 1016 + 1017 + 2 @@ -2367,22 +2392,22 @@ 1 2 - 4689 + 4662 2 3 - 691 + 659 3 - 20 - 445 + 23 + 436 - 20 - 1697 - 48 + 32 + 1696 + 41 @@ -2398,7 +2423,7 @@ 1 2 - 5875 + 5800 @@ -2408,15 +2433,15 @@ files - 16948 + 17168 id - 16948 + 17168 name - 16948 + 17168 @@ -2430,7 +2455,7 @@ 1 2 - 16948 + 17168 @@ -2446,7 +2471,7 @@ 1 2 - 16948 + 17168 @@ -2456,15 +2481,15 @@ folders - 4774 + 4792 id - 4774 + 4792 name - 4774 + 4792 @@ -2478,7 +2503,7 @@ 1 2 - 4774 + 4792 @@ -2494,7 +2519,7 @@ 1 2 - 4774 + 4792 @@ -2504,31 +2529,31 @@ locations_default - 8504708 + 8508604 id - 8504708 + 8508604 file - 16948 + 17168 start_line - 30559 + 30674 start_column - 5045 + 5064 end_line - 30559 + 30674 end_column - 5110 + 5129 @@ -2542,7 +2567,7 @@ 1 2 - 8504708 + 8508604 @@ -2558,7 +2583,7 @@ 1 2 - 8504708 + 8508604 @@ -2574,7 +2599,7 @@ 1 2 - 8504708 + 8508604 @@ -2590,7 +2615,7 @@ 1 2 - 8504708 + 8508604 @@ -2606,7 +2631,7 @@ 1 2 - 8504708 + 8508604 @@ -2621,73 +2646,68 @@ 1 - 34 - 1397 + 32 + 1337 - 34 - 52 - 1280 + 32 + 48 + 1311 - 52 - 73 - 1345 + 48 + 72 + 1376 - 73 + 72 94 - 1319 + 1493 94 127 - 1280 + 1298 127 - 168 - 1293 + 169 + 1311 - 168 - 215 - 1306 + 169 + 216 + 1298 - 215 - 269 - 1280 + 216 + 271 + 1298 - 269 - 350 - 1293 + 271 + 353 + 1311 - 350 - 471 - 1293 + 353 + 475 + 1298 - 474 - 717 - 1280 + 476 + 721 + 1298 - 718 - 1367 - 1280 + 724 + 1480 + 1298 - 1390 - 15687 - 1280 - - - 22816 + 1481 22817 - 12 + 1233 @@ -2702,68 +2722,68 @@ 1 - 8 - 1500 + 7 + 1116 - 8 - 11 - 1371 + 7 + 10 + 1545 - 11 - 14 - 1487 + 10 + 13 + 1389 - 14 - 17 - 1423 + 13 + 16 + 1493 - 17 - 21 - 1436 + 16 + 20 + 1571 - 21 - 26 - 1371 + 20 + 25 + 1363 - 26 - 32 - 1345 + 25 + 31 + 1441 - 32 - 39 - 1397 + 31 + 38 + 1350 - 39 - 51 - 1384 + 38 + 49 + 1441 - 51 - 75 - 1293 + 49 + 69 + 1324 - 75 - 125 - 1280 + 69 + 117 + 1298 - 125 - 313 - 1280 + 119 + 257 + 1298 - 323 + 260 2337 - 375 + 532 @@ -2779,67 +2799,67 @@ 1 16 - 1280 + 1415 16 25 - 1410 + 1428 25 32 - 1358 + 1363 32 41 - 1358 + 1376 41 47 - 1500 + 1506 47 54 - 1526 + 1532 54 62 - 1332 + 1363 62 - 68 - 1293 + 69 + 1402 - 68 - 76 - 1371 + 69 + 77 + 1428 - 76 - 85 - 1280 + 77 + 87 + 1350 - 85 - 97 - 1293 + 87 + 101 + 1324 - 97 - 119 - 1293 + 101 + 130 + 1298 - 119 + 130 357 - 646 + 376 @@ -2855,67 +2875,67 @@ 1 8 - 1461 + 1558 8 11 - 1397 + 1467 11 14 - 1487 + 1506 14 17 - 1410 + 1415 17 21 - 1461 + 1467 21 26 - 1371 + 1337 26 32 - 1345 + 1363 32 39 - 1397 + 1415 39 51 - 1384 + 1402 51 75 - 1293 + 1298 75 - 125 - 1280 + 126 + 1311 - 125 - 313 - 1280 + 126 + 343 + 1298 - 323 + 354 2337 - 375 + 324 @@ -2931,67 +2951,67 @@ 1 20 - 1306 + 1441 20 28 - 1280 + 1298 28 36 - 1371 + 1389 36 45 - 1358 + 1363 45 50 - 1306 + 1311 50 57 - 1345 + 1350 57 64 - 1371 + 1376 64 71 - 1280 + 1298 71 78 - 1397 + 1376 78 87 - 1384 + 1428 87 - 98 - 1280 + 99 + 1402 - 98 - 116 - 1293 + 99 + 120 + 1363 - 116 + 120 367 - 970 + 766 @@ -3007,72 +3027,67 @@ 1 2 - 1513 + 1519 2 - 5 - 1759 + 4 + 1753 5 6 - 3532 + 3545 6 10 - 2445 + 2454 10 - 16 - 2302 + 17 + 2805 - 16 - 21 - 2419 + 17 + 24 + 2441 - 21 - 37 - 2367 + 24 + 42 + 2350 - 37 - 70 - 2315 + 42 + 78 + 2337 - 70 - 113 - 2328 + 78 + 119 + 2311 - 113 - 163 - 2302 + 119 + 173 + 2324 - 163 - 256 - 2315 + 173 + 279 + 2311 - 257 - 673 - 2302 + 281 + 866 + 2311 - 678 - 4748 - 2302 - - - 4761 - 9964 - 349 + 866 + 10012 + 2207 @@ -3088,47 +3103,47 @@ 1 2 - 10699 + 10713 2 3 - 4787 + 4753 3 6 - 2328 + 2337 6 - 10 - 2729 + 9 + 2363 - 10 - 15 - 2393 + 9 + 14 + 2792 - 15 - 24 - 2445 + 14 + 22 + 2324 - 24 - 64 - 2302 + 22 + 57 + 2311 - 64 - 378 - 2302 + 57 + 287 + 2311 - 393 - 1310 - 569 + 291 + 1322 + 766 @@ -3144,72 +3159,72 @@ 1 2 - 1513 + 1519 2 3 - 1578 + 1584 3 4 - 2548 + 2558 4 6 - 2445 + 2441 6 8 - 1578 + 1584 8 - 12 - 2302 + 13 + 2818 - 12 - 16 - 2535 + 13 + 18 + 2610 - 16 - 26 - 2406 + 18 + 30 + 2506 - 26 - 41 - 2406 + 30 + 43 + 2363 - 41 - 54 - 2380 + 43 + 57 + 2428 - 54 - 68 - 2458 + 57 + 70 + 2324 - 68 - 85 - 2419 + 70 + 89 + 2350 - 85 - 111 - 2367 + 89 + 116 + 2311 - 111 + 116 203 - 1617 + 1272 @@ -3225,41 +3240,41 @@ 1 2 - 12588 + 12648 2 3 - 6675 + 6714 3 4 - 2225 + 2363 4 5 - 1746 + 1792 5 7 - 2419 + 2324 7 12 - 2419 + 2337 12 34 - 2302 + 2311 40 - 240 + 241 181 @@ -3276,67 +3291,67 @@ 1 2 - 1513 + 1519 2 4 - 1759 + 1766 4 5 - 3635 + 3636 5 8 - 2652 + 2662 8 - 12 - 2225 + 13 + 2792 - 12 - 16 - 2561 + 13 + 17 + 2311 - 16 - 26 - 2367 + 17 + 28 + 2376 - 26 - 41 - 2367 + 28 + 42 + 2428 - 41 - 56 - 2471 + 42 + 57 + 2415 - 56 - 70 - 2406 + 57 + 71 + 2389 - 70 - 86 - 2354 + 71 + 88 + 2363 - 86 - 110 - 2341 + 88 + 113 + 2311 - 110 + 113 203 - 1901 + 1701 @@ -3352,71 +3367,71 @@ 1 2 - 439 + 441 2 3 - 621 + 623 3 4 - 232 + 233 4 5 - 271 + 272 5 6 - 245 + 246 6 9 - 465 + 467 9 16 - 414 + 415 16 41 - 388 + 389 - 45 - 173 - 388 + 46 + 172 + 389 - 179 + 181 773 - 388 + 389 - 795 - 2929 - 388 + 791 + 2919 + 389 - 2936 - 8174 - 388 + 2920 + 8125 + 389 - 8240 - 26107 - 388 + 8227 + 25706 + 389 - 33980 - 35323 + 33875 + 34983 25 @@ -3433,52 +3448,52 @@ 1 2 - 1500 + 1506 2 3 - 543 + 545 3 4 - 426 + 428 4 10 - 388 + 389 10 39 - 388 + 389 39 139 - 388 + 389 - 146 + 147 387 - 388 + 389 - 399 - 749 - 388 + 397 + 748 + 389 - 765 - 964 - 388 + 769 + 963 + 389 964 - 1310 - 245 + 1322 + 246 @@ -3494,62 +3509,62 @@ 1 2 - 543 + 545 2 3 - 672 + 675 3 4 - 336 + 337 4 6 - 401 + 402 6 9 - 465 + 467 9 19 - 388 + 389 19 - 63 - 388 + 64 + 389 66 - 183 - 388 + 184 + 402 - 183 - 380 - 388 + 201 + 390 + 389 - 392 - 736 - 388 + 418 + 742 + 389 - 750 - 1013 - 388 + 752 + 1025 + 389 1028 - 1385 - 297 + 1382 + 285 @@ -3565,62 +3580,62 @@ 1 2 - 543 + 545 2 3 - 672 + 675 3 4 - 336 + 337 4 6 - 401 + 402 6 9 - 465 + 467 9 19 - 388 + 389 19 64 - 388 + 389 66 184 - 401 + 389 - 205 - 400 - 388 + 184 + 381 + 389 - 431 + 396 752 - 388 + 389 - 761 - 1038 - 388 + 753 + 1034 + 402 - 1048 - 1390 - 284 + 1050 + 1386 + 285 @@ -3636,52 +3651,52 @@ 1 2 - 1280 + 1285 2 3 - 724 + 727 3 4 - 439 + 441 4 6 - 414 + 415 6 16 - 388 + 389 16 37 - 401 + 389 37 67 - 388 + 402 67 103 - 388 + 389 - 103 - 126 - 388 + 104 + 127 + 402 - 126 + 127 177 - 232 + 220 @@ -3697,72 +3712,72 @@ 1 2 - 310 + 311 3 4 - 3519 + 3532 4 6 - 2639 + 2636 6 9 - 2393 + 2415 9 14 - 2380 + 2350 14 21 - 2497 + 2467 21 34 - 2328 + 2324 34 - 66 - 2341 + 64 + 2311 - 66 - 107 - 2315 + 64 + 103 + 2337 - 107 - 158 - 2328 + 103 + 152 + 2311 - 158 - 243 - 2302 + 152 + 230 + 2311 - 243 - 574 - 2302 + 230 + 525 + 2311 - 580 - 2918 - 2302 + 528 + 2539 + 2311 - 2988 - 9852 - 595 + 2543 + 9864 + 740 @@ -3778,47 +3793,47 @@ 1 2 - 10699 + 10713 2 3 - 4787 + 4753 3 6 - 2328 + 2337 6 - 10 - 2729 + 9 + 2363 - 10 - 15 - 2393 + 9 + 14 + 2792 - 15 - 24 - 2445 + 14 + 22 + 2324 - 24 - 64 - 2302 + 22 + 57 + 2311 - 64 - 378 - 2302 + 57 + 287 + 2311 - 393 - 1294 - 569 + 291 + 1306 + 766 @@ -3834,42 +3849,42 @@ 1 2 - 12510 + 12428 2 3 - 6287 + 6532 3 4 - 2458 + 2532 4 5 - 1668 + 1753 5 7 - 2341 + 2207 7 12 - 2471 + 2441 12 27 - 2406 + 2363 27 - 35 - 414 + 36 + 415 @@ -3885,67 +3900,67 @@ 1 3 - 1513 + 1519 3 4 - 3674 + 3688 4 6 - 2716 + 2714 6 8 - 1643 + 1649 8 - 12 - 2367 + 13 + 2766 - 12 - 16 - 2406 + 13 + 17 + 2363 - 16 - 26 - 2484 + 17 + 28 + 2415 - 26 - 41 - 2341 + 28 + 42 + 2415 - 41 - 54 - 2419 + 42 + 55 + 2337 - 54 - 68 - 2419 + 55 + 69 + 2441 - 68 - 84 - 2393 + 69 + 86 + 2415 - 84 - 108 - 2393 + 86 + 112 + 2376 - 108 + 112 200 - 1785 + 1571 @@ -3961,72 +3976,72 @@ 1 2 - 1500 + 1506 2 3 - 1617 + 1623 3 4 - 2548 + 2558 4 6 - 2406 + 2402 6 8 - 1643 + 1649 8 13 - 2768 + 2688 13 18 - 2574 + 2636 18 30 - 2341 + 2402 30 - 45 - 2471 + 44 + 2389 - 45 - 60 - 2484 + 44 + 58 + 2337 - 60 - 75 - 2354 + 58 + 72 + 2324 - 75 - 94 - 2367 + 72 + 90 + 2389 - 94 - 121 - 2367 + 90 + 117 + 2311 - 121 + 117 202 - 1112 + 1454 @@ -4042,17 +4057,17 @@ 1 2 - 349 + 350 2 3 - 478 + 480 3 5 - 401 + 402 5 @@ -4062,51 +4077,51 @@ 6 8 - 465 + 467 8 14 - 388 + 389 14 28 - 388 + 389 28 - 66 - 388 + 68 + 389 69 - 262 - 388 + 258 + 389 - 268 - 1065 - 388 + 264 + 1063 + 389 - 1106 - 3376 - 388 + 1113 + 3378 + 389 - 3708 - 8055 - 388 + 3687 + 8035 + 389 - 8112 - 10395 - 388 + 8096 + 10367 + 389 - 10483 - 18241 + 10416 + 17990 116 @@ -4123,52 +4138,52 @@ 1 2 - 1436 + 1441 2 3 - 608 + 610 3 4 - 426 + 428 4 9 - 401 + 402 9 - 40 - 388 + 41 + 389 - 41 - 121 - 388 + 42 + 123 + 389 143 - 410 - 401 + 406 + 389 - 419 - 772 - 388 + 406 + 760 + 389 - 794 - 1007 - 388 + 771 + 994 + 389 - 1008 - 1277 - 284 + 1006 + 1289 + 298 @@ -4184,67 +4199,67 @@ 1 2 - 517 + 519 2 3 - 672 + 675 3 4 - 297 + 298 4 6 - 401 + 402 6 9 - 452 + 454 9 16 - 414 + 415 16 - 38 - 388 + 39 + 389 39 136 - 401 + 389 - 139 - 357 - 388 + 136 + 344 + 389 - 359 - 676 - 388 + 353 + 637 + 389 - 687 - 1018 - 388 + 675 + 1011 + 389 - 1020 - 1286 - 388 + 1011 + 1272 + 389 - 1386 + 1284 1387 - 12 + 25 @@ -4260,62 +4275,62 @@ 1 2 - 892 + 896 2 3 - 310 + 311 3 4 - 504 + 506 4 5 - 349 + 350 5 8 - 439 + 441 8 18 - 388 + 389 19 33 - 388 + 389 33 49 - 388 + 389 49 64 - 388 + 402 64 - 81 - 388 + 82 + 428 - 81 - 94 - 414 + 82 + 95 + 402 - 94 + 95 112 - 258 + 220 @@ -4331,67 +4346,67 @@ 1 2 - 517 + 519 2 3 - 672 + 675 3 4 - 297 + 298 4 6 - 401 + 402 6 9 - 452 + 454 9 16 - 414 + 415 16 - 38 - 388 + 39 + 402 - 38 - 137 - 388 + 48 + 141 + 389 - 139 - 346 - 388 + 142 + 352 + 389 - 354 + 359 637 - 388 + 389 - 641 - 995 - 388 + 674 + 999 + 389 - 997 - 1231 - 388 + 1010 + 1283 + 389 - 1283 + 1381 1382 - 25 + 12 @@ -4401,19 +4416,19 @@ ruby_alias_def - 1256 + 1244 id - 1256 + 1244 alias - 1256 + 1244 name - 1256 + 1244 @@ -4427,7 +4442,7 @@ 1 2 - 1256 + 1244 @@ -4443,7 +4458,7 @@ 1 2 - 1256 + 1244 @@ -4459,7 +4474,7 @@ 1 2 - 1256 + 1244 @@ -4475,7 +4490,7 @@ 1 2 - 1256 + 1244 @@ -4491,7 +4506,7 @@ 1 2 - 1256 + 1244 @@ -4507,7 +4522,7 @@ 1 2 - 1256 + 1244 @@ -4583,7 +4598,7 @@ 1 2 - 3 + 2 @@ -4599,7 +4614,7 @@ 1 2 - 3 + 2 @@ -4620,19 +4635,19 @@ ruby_argument_list_child - 822785 + 823783 ruby_argument_list - 662859 + 664257 index - 426 + 428 child - 822785 + 823783 @@ -4646,17 +4661,17 @@ 1 2 - 561206 + 562976 2 3 - 64469 + 64088 3 34 - 37183 + 37193 @@ -4672,17 +4687,17 @@ 1 2 - 561206 + 562976 2 3 - 64469 + 64088 3 34 - 37183 + 37193 @@ -4717,27 +4732,27 @@ 11 - 21 + 20 38 22 - 43 + 42 38 - 56 - 375 + 55 + 372 38 - 903 - 7858 + 900 + 7800 38 - 51234 - 51235 + 51150 + 51151 12 @@ -4773,27 +4788,27 @@ 11 - 21 + 20 38 22 - 43 + 42 38 - 56 - 375 + 55 + 372 38 - 903 - 7858 + 900 + 7800 38 - 51234 - 51235 + 51150 + 51151 12 @@ -4810,7 +4825,7 @@ 1 2 - 822785 + 823783 @@ -4826,7 +4841,7 @@ 1 2 - 822785 + 823783 @@ -4836,22 +4851,22 @@ ruby_argument_list_def - 663118 + 664517 id - 663118 + 664517 ruby_array_child - 698871 + 699082 ruby_array - 237321 + 237416 index @@ -4859,7 +4874,7 @@ child - 698871 + 699082 @@ -4873,17 +4888,17 @@ 1 2 - 11990 + 11987 2 3 - 212002 + 212081 3 63361 - 13329 + 13348 @@ -4899,17 +4914,17 @@ 1 2 - 11990 + 11987 2 3 - 212002 + 212081 3 63361 - 13329 + 13348 @@ -4949,7 +4964,7 @@ 11 - 237322 + 237417 1294 @@ -4990,7 +5005,7 @@ 11 - 237322 + 237417 1294 @@ -5007,7 +5022,7 @@ 1 2 - 698871 + 699082 @@ -5023,7 +5038,7 @@ 1 2 - 698871 + 699082 @@ -5033,11 +5048,11 @@ ruby_array_def - 245466 + 245561 id - 245466 + 245561 @@ -5110,7 +5125,7 @@ 1 2 - 3 + 2 @@ -5126,7 +5141,7 @@ 1 2 - 3 + 2 @@ -5158,7 +5173,7 @@ 1 2 - 3 + 2 @@ -5174,7 +5189,7 @@ 1 2 - 3 + 2 @@ -5221,7 +5236,7 @@ 1 2 - 3 + 2 @@ -5237,7 +5252,7 @@ 1 2 - 3 + 2 @@ -5287,19 +5302,19 @@ ruby_assignment_def - 130604 + 130246 id - 130604 + 130246 left - 130604 + 130246 right - 130604 + 130246 @@ -5313,7 +5328,7 @@ 1 2 - 130604 + 130246 @@ -5329,7 +5344,7 @@ 1 2 - 130604 + 130246 @@ -5345,7 +5360,7 @@ 1 2 - 130604 + 130246 @@ -5361,7 +5376,7 @@ 1 2 - 130604 + 130246 @@ -5377,7 +5392,7 @@ 1 2 - 130604 + 130246 @@ -5393,7 +5408,7 @@ 1 2 - 130604 + 130246 @@ -5403,23 +5418,23 @@ ruby_ast_node_info - 8775135 + 8791047 node - 8775135 + 8791047 parent - 2870167 + 2884450 parent_index - 2781 + 2792 loc - 8492468 + 8496293 @@ -5433,7 +5448,7 @@ 1 2 - 8775135 + 8791047 @@ -5449,7 +5464,7 @@ 1 2 - 8775135 + 8791047 @@ -5465,7 +5480,7 @@ 1 2 - 8775135 + 8791047 @@ -5481,27 +5496,27 @@ 1 2 - 312864 + 325272 2 3 - 393001 + 393074 3 4 - 1606523 + 1608542 4 5 - 344781 + 344466 5 216 - 212996 + 213094 @@ -5517,27 +5532,27 @@ 1 2 - 312864 + 325272 2 3 - 393001 + 393074 3 4 - 1606523 + 1608542 4 5 - 344781 + 344466 5 216 - 212996 + 213094 @@ -5553,27 +5568,27 @@ 1 2 - 312864 + 325272 2 3 - 393001 + 393074 3 4 - 1606523 + 1608542 4 5 - 344781 + 344466 5 216 - 212996 + 213094 @@ -5589,56 +5604,51 @@ 1 2 - 401 + 649 2 3 - 245 + 389 3 - 4 - 388 + 5 + 233 - 4 + 5 6 - 232 + 233 6 - 7 - 232 + 9 + 233 - 7 - 10 - 232 + 9 + 21 + 246 - 10 - 22 - 245 + 21 + 48 + 220 - 22 - 50 - 219 + 48 + 127 + 220 - 50 - 129 - 219 + 130 + 946 + 220 - 132 - 949 - 219 - - - 1419 - 221843 + 1416 + 222113 142 @@ -5655,56 +5665,51 @@ 1 2 - 401 + 649 2 3 - 245 + 389 3 - 4 - 388 + 5 + 233 - 4 + 5 6 - 232 + 233 6 - 7 - 232 + 9 + 233 - 7 - 10 - 232 + 9 + 21 + 246 - 10 - 22 - 245 + 21 + 48 + 220 - 22 - 50 - 219 + 48 + 127 + 220 - 50 - 129 - 219 + 130 + 946 + 220 - 132 - 949 - 219 - - - 1419 - 221843 + 1416 + 222113 142 @@ -5721,56 +5726,51 @@ 1 2 - 401 + 649 2 3 - 245 + 389 3 - 4 - 388 + 5 + 233 - 4 + 5 6 - 232 + 233 6 - 7 - 232 + 9 + 233 - 7 - 10 - 232 + 9 + 21 + 246 - 10 - 22 - 245 + 21 + 48 + 220 - 22 - 50 - 219 + 48 + 127 + 220 - 50 - 129 - 219 + 130 + 946 + 220 - 132 - 949 - 219 - - - 1419 - 221660 + 1416 + 221838 142 @@ -5787,12 +5787,12 @@ 1 2 - 8209814 + 8202149 2 4 - 282654 + 294143 @@ -5808,12 +5808,12 @@ 1 2 - 8209814 + 8202149 2 4 - 282654 + 294143 @@ -5829,12 +5829,12 @@ 1 2 - 8212169 + 8205110 2 3 - 280299 + 291182 @@ -5844,11 +5844,11 @@ ruby_bare_string_child - 14923 + 14936 ruby_bare_string - 11474 + 11487 index @@ -5856,7 +5856,7 @@ child - 14923 + 14936 @@ -5870,7 +5870,7 @@ 1 2 - 11146 + 11159 2 @@ -5891,7 +5891,7 @@ 1 2 - 11146 + 11159 2 @@ -5926,7 +5926,7 @@ 4 - 11475 + 11488 19 @@ -5957,7 +5957,7 @@ 4 - 11475 + 11488 19 @@ -5974,7 +5974,7 @@ 1 2 - 14923 + 14936 @@ -5990,7 +5990,7 @@ 1 2 - 14923 + 14936 @@ -6000,30 +6000,30 @@ ruby_bare_string_def - 11474 + 11487 id - 11474 + 11487 ruby_bare_symbol_child - 2137 + 2106 ruby_bare_symbol - 2137 + 2106 index - 3 + 2 child - 2137 + 2106 @@ -6037,7 +6037,7 @@ 1 2 - 2137 + 2106 @@ -6053,7 +6053,7 @@ 1 2 - 2137 + 2106 @@ -6067,9 +6067,9 @@ 12 - 705 - 706 - 3 + 709 + 710 + 2 @@ -6083,9 +6083,9 @@ 12 - 705 - 706 - 3 + 709 + 710 + 2 @@ -6101,7 +6101,7 @@ 1 2 - 2137 + 2106 @@ -6117,7 +6117,7 @@ 1 2 - 2137 + 2106 @@ -6127,11 +6127,11 @@ ruby_bare_symbol_def - 2137 + 2106 id - 2137 + 2106 @@ -6365,11 +6365,11 @@ ruby_begin_child - 7555 + 7535 ruby_begin - 2533 + 2523 index @@ -6377,7 +6377,7 @@ child - 7555 + 7535 @@ -6396,22 +6396,22 @@ 2 3 - 1325 + 1317 3 4 - 518 + 516 4 5 - 211 + 212 5 8 - 231 + 230 8 @@ -6437,22 +6437,22 @@ 2 3 - 1325 + 1317 3 4 - 518 + 516 4 5 - 211 + 212 5 8 - 231 + 230 8 @@ -6512,17 +6512,17 @@ 84 - 183 + 185 3 - 315 - 1045 + 314 + 1043 3 - 2369 - 2534 + 2359 + 2524 2 @@ -6578,17 +6578,17 @@ 84 - 183 + 185 3 - 315 - 1045 + 314 + 1043 3 - 2369 - 2534 + 2359 + 2524 2 @@ -6605,7 +6605,7 @@ 1 2 - 7555 + 7535 @@ -6621,7 +6621,7 @@ 1 2 - 7555 + 7535 @@ -6631,26 +6631,26 @@ ruby_begin_def - 2533 + 2523 id - 2533 + 2523 ruby_binary_def - 67989 + 67730 id - 67989 + 67730 left - 67989 + 67730 operator @@ -6658,7 +6658,7 @@ right - 67989 + 67730 @@ -6672,7 +6672,7 @@ 1 2 - 67989 + 67730 @@ -6688,7 +6688,7 @@ 1 2 - 67989 + 67730 @@ -6704,7 +6704,7 @@ 1 2 - 67989 + 67730 @@ -6720,7 +6720,7 @@ 1 2 - 67989 + 67730 @@ -6736,7 +6736,7 @@ 1 2 - 67989 + 67730 @@ -6752,7 +6752,7 @@ 1 2 - 67989 + 67730 @@ -6767,67 +6767,67 @@ 155 - 178 + 179 2 - 230 - 370 + 231 + 369 2 474 - 557 + 559 2 603 - 674 + 666 2 749 - 808 + 813 2 - 950 - 982 + 949 + 969 2 - 996 - 1015 + 1000 + 1010 2 1248 - 1292 + 1317 2 - 1355 - 1621 + 1348 + 1633 2 - 1822 - 1978 + 1820 + 1968 2 - 2883 - 3120 + 2381 + 3287 2 - 6102 - 6755 + 6116 + 6739 2 - 31084 - 31085 + 31159 + 31160 1 @@ -6843,67 +6843,67 @@ 155 - 178 + 179 2 - 230 - 370 + 231 + 369 2 474 - 557 + 559 2 603 - 674 + 666 2 749 - 808 + 813 2 - 950 - 982 + 949 + 969 2 - 996 - 1015 + 1000 + 1010 2 1248 - 1292 + 1317 2 - 1355 - 1621 + 1348 + 1633 2 - 1822 - 1978 + 1820 + 1968 2 - 2883 - 3120 + 2381 + 3287 2 - 6102 - 6755 + 6116 + 6739 2 - 31084 - 31085 + 31159 + 31160 1 @@ -6919,67 +6919,67 @@ 155 - 178 + 179 2 - 230 - 370 + 231 + 369 2 474 - 557 + 559 2 603 - 674 + 666 2 749 - 808 + 813 2 - 950 - 982 + 949 + 969 2 - 996 - 1015 + 1000 + 1010 2 1248 - 1292 + 1317 2 - 1355 - 1621 + 1348 + 1633 2 - 1822 - 1978 + 1820 + 1968 2 - 2883 - 3120 + 2381 + 3287 2 - 6102 - 6755 + 6116 + 6739 2 - 31084 - 31085 + 31159 + 31160 1 @@ -6996,7 +6996,7 @@ 1 2 - 67989 + 67730 @@ -7012,7 +7012,7 @@ 1 2 - 67989 + 67730 @@ -7028,7 +7028,7 @@ 1 2 - 67989 + 67730 @@ -7038,15 +7038,15 @@ ruby_block_argument_child - 6048 + 6050 ruby_block_argument - 6048 + 6050 child - 6048 + 6050 @@ -7060,7 +7060,7 @@ 1 2 - 6048 + 6050 @@ -7076,7 +7076,7 @@ 1 2 - 6048 + 6050 @@ -7086,22 +7086,22 @@ ruby_block_argument_def - 6048 + 6050 id - 6048 + 6050 ruby_block_child - 96749 + 97203 ruby_block - 96607 + 97060 index @@ -7109,7 +7109,7 @@ child - 96749 + 97203 @@ -7123,7 +7123,7 @@ 1 2 - 96516 + 96969 2 @@ -7144,7 +7144,7 @@ 1 2 - 96516 + 96969 2 @@ -7173,8 +7173,8 @@ 12 - 7467 - 7468 + 7474 + 7475 12 @@ -7199,8 +7199,8 @@ 12 - 7467 - 7468 + 7474 + 7475 12 @@ -7217,7 +7217,7 @@ 1 2 - 96749 + 97203 @@ -7233,7 +7233,7 @@ 1 2 - 96749 + 97203 @@ -7243,11 +7243,11 @@ ruby_block_def - 96904 + 97359 id - 96904 + 97359 @@ -7313,15 +7313,15 @@ ruby_block_parameters - 10443 + 10459 ruby_block - 10443 + 10459 parameters - 10443 + 10459 @@ -7335,7 +7335,7 @@ 1 2 - 10443 + 10459 @@ -7351,7 +7351,7 @@ 1 2 - 10443 + 10459 @@ -7361,11 +7361,11 @@ ruby_block_parameters_child - 27363 + 27190 ruby_block_parameters - 23501 + 23336 index @@ -7373,7 +7373,7 @@ child - 27363 + 27190 @@ -7387,12 +7387,12 @@ 1 2 - 20121 + 19964 2 3 - 3030 + 3022 3 @@ -7413,12 +7413,12 @@ 1 2 - 20121 + 19964 2 3 - 3030 + 3022 3 @@ -7452,13 +7452,13 @@ 3 - 1073 - 1074 + 1070 + 1071 3 - 7460 - 7461 + 7405 + 7406 3 @@ -7488,13 +7488,13 @@ 3 - 1073 - 1074 + 1070 + 1071 3 - 7460 - 7461 + 7405 + 7406 3 @@ -7511,7 +7511,7 @@ 1 2 - 27363 + 27190 @@ -7527,7 +7527,7 @@ 1 2 - 27363 + 27190 @@ -7537,26 +7537,162 @@ ruby_block_parameters_def - 23501 + 23336 id - 23501 + 23336 + + ruby_block_parameters_locals + 16 + + + ruby_block_parameters + 12 + + + index + 2 + + + locals + 16 + + + + + ruby_block_parameters + index + + + 12 + + + 1 + 2 + 8 + + + 2 + 3 + 4 + + + + + + + ruby_block_parameters + locals + + + 12 + + + 1 + 2 + 8 + + + 2 + 3 + 4 + + + + + + + index + ruby_block_parameters + + + 12 + + + 4 + 5 + 1 + + + 12 + 13 + 1 + + + + + + + index + locals + + + 12 + + + 4 + 5 + 1 + + + 12 + 13 + 1 + + + + + + + locals + ruby_block_parameters + + + 12 + + + 1 + 2 + 16 + + + + + + + locals + index + + + 12 + + + 1 + 2 + 16 + + + + + + + ruby_break_child - 349 + 350 ruby_break - 349 + 350 child - 349 + 350 @@ -7570,7 +7706,7 @@ 1 2 - 349 + 350 @@ -7586,7 +7722,7 @@ 1 2 - 349 + 350 @@ -7596,26 +7732,26 @@ ruby_break_def - 3343 + 3338 id - 3343 + 3338 ruby_call_arguments - 660078 + 661504 ruby_call - 660078 + 661504 arguments - 660078 + 661504 @@ -7629,7 +7765,7 @@ 1 2 - 660078 + 661504 @@ -7645,7 +7781,7 @@ 1 2 - 660078 + 661504 @@ -7655,15 +7791,15 @@ ruby_call_block - 230967 + 232457 ruby_call - 230967 + 232457 block - 230967 + 232457 @@ -7677,7 +7813,7 @@ 1 2 - 230967 + 232457 @@ -7693,7 +7829,7 @@ 1 2 - 230967 + 232457 @@ -7703,20 +7839,31 @@ ruby_call_def - 961220 + 965401 id - 961220 + 965401 + + + + + + ruby_call_method + 965401 + + + ruby_call + 965401 method - 961220 + 965401 - id + ruby_call method @@ -7725,7 +7872,7 @@ 1 2 - 961220 + 965401 @@ -7733,7 +7880,7 @@ method - id + ruby_call 12 @@ -7741,7 +7888,55 @@ 1 2 - 961220 + 965401 + + + + + + + + + ruby_call_operator + 540944 + + + ruby_call + 540944 + + + operator + 540944 + + + + + ruby_call + operator + + + 12 + + + 1 + 2 + 540944 + + + + + + + operator + ruby_call + + + 12 + + + 1 + 2 + 540944 @@ -7751,15 +7946,15 @@ ruby_call_receiver - 538536 + 540944 ruby_call - 538536 + 540944 receiver - 538536 + 540944 @@ -7773,7 +7968,7 @@ 1 2 - 538536 + 540944 @@ -7789,7 +7984,7 @@ 1 2 - 538536 + 540944 @@ -7799,7 +7994,7 @@ ruby_case_child - 4123 + 4141 ruby_case__ @@ -7811,7 +8006,7 @@ child - 4123 + 4141 @@ -7830,17 +8025,17 @@ 2 3 - 324 + 315 3 4 - 497 + 504 4 5 - 185 + 189 5 @@ -7871,17 +8066,17 @@ 2 3 - 324 + 315 3 4 - 497 + 504 4 5 - 185 + 189 5 @@ -7930,13 +8125,13 @@ 6 - 31 + 32 56 6 - 114 - 273 + 115 + 276 6 @@ -7981,13 +8176,13 @@ 6 - 31 + 32 56 6 - 114 - 273 + 115 + 276 6 @@ -8009,7 +8204,7 @@ 1 2 - 4123 + 4141 @@ -8025,7 +8220,7 @@ 1 2 - 4123 + 4141 @@ -8046,19 +8241,19 @@ ruby_case_match_clauses - 2 + 0 ruby_case_match - 2 + 0 index - 1 + 0 clauses - 2 + 0 @@ -8068,13 +8263,7 @@ 12 - - - 1 - 2 - 2 - - + @@ -8084,13 +8273,7 @@ 12 - - - 1 - 2 - 2 - - + @@ -8100,13 +8283,7 @@ 12 - - - 2 - 3 - 1 - - + @@ -8116,13 +8293,7 @@ 12 - - - 2 - 3 - 1 - - + @@ -8162,15 +8333,15 @@ ruby_case_match_def - 2 + 0 id - 2 + 0 value - 2 + 0 @@ -8196,13 +8367,7 @@ 12 - - - 1 - 2 - 2 - - + @@ -8232,7 +8397,7 @@ 1 2 - 3 + 2 @@ -8248,7 +8413,7 @@ 1 2 - 3 + 2 @@ -8306,11 +8471,11 @@ ruby_chained_string_child - 3380 + 3353 ruby_chained_string - 894 + 885 index @@ -8318,7 +8483,7 @@ child - 3380 + 3353 @@ -8332,7 +8497,7 @@ 2 3 - 308 + 302 3 @@ -8347,7 +8512,7 @@ 5 6 - 126 + 122 6 @@ -8373,7 +8538,7 @@ 2 3 - 308 + 302 3 @@ -8388,7 +8553,7 @@ 5 6 - 126 + 122 6 @@ -8447,23 +8612,23 @@ 3 - 81 - 82 + 80 + 81 3 - 124 - 125 + 123 + 124 3 - 186 - 187 + 185 + 186 3 - 284 - 285 + 281 + 282 6 @@ -8513,23 +8678,23 @@ 3 - 81 - 82 + 80 + 81 3 - 124 - 125 + 123 + 124 3 - 186 - 187 + 185 + 186 3 - 284 - 285 + 281 + 282 6 @@ -8546,7 +8711,7 @@ 1 2 - 3380 + 3353 @@ -8562,7 +8727,7 @@ 1 2 - 3380 + 3353 @@ -8572,30 +8737,30 @@ ruby_chained_string_def - 894 + 885 id - 894 + 885 ruby_class_child - 131549 + 130958 ruby_class - 15128 + 15183 index - 1045 + 1055 child - 131549 + 130958 @@ -8609,57 +8774,57 @@ 1 2 - 3260 + 3290 2 3 - 2362 + 2407 3 4 - 1559 + 1556 4 5 - 1250 + 1263 5 6 - 957 + 961 6 7 - 831 + 838 7 9 - 1127 + 1118 9 13 - 1269 + 1266 13 21 - 1184 + 1169 21 - 76 - 1137 + 84 + 1143 - 77 - 333 - 185 + 85 + 336 + 167 @@ -8675,57 +8840,57 @@ 1 2 - 3260 + 3290 2 3 - 2362 + 2407 3 4 - 1559 + 1556 4 5 - 1250 + 1263 5 6 - 957 + 961 6 7 - 831 + 838 7 9 - 1127 + 1118 9 13 - 1269 + 1266 13 21 - 1184 + 1169 21 - 76 - 1137 + 84 + 1143 - 77 - 333 - 185 + 85 + 336 + 167 @@ -8741,72 +8906,72 @@ 1 2 - 88 + 37 2 3 - 3 + 63 3 4 - 94 + 81 4 5 - 103 + 113 5 7 - 75 + 81 7 9 - 85 + 81 9 12 - 91 + 88 12 - 20 + 19 85 - 20 - 30 - 78 + 19 + 29 + 81 - 31 - 52 - 78 + 30 + 56 + 81 - 53 - 89 - 78 + 56 + 94 + 81 - 90 - 208 - 78 + 96 + 228 + 81 - 214 - 1200 - 78 + 237 + 2116 + 81 - 1372 - 4803 - 25 + 2516 + 4819 + 12 @@ -8822,72 +8987,72 @@ 1 2 - 88 + 37 2 3 - 3 + 63 3 4 - 94 + 81 4 5 - 103 + 113 5 7 - 75 + 81 7 9 - 85 + 81 9 12 - 91 + 88 12 - 20 + 19 85 - 20 - 30 - 78 + 19 + 29 + 81 - 31 - 52 - 78 + 30 + 56 + 81 - 53 - 89 - 78 + 56 + 94 + 81 - 90 - 208 - 78 + 96 + 228 + 81 - 214 - 1200 - 78 + 237 + 2116 + 81 - 1372 - 4803 - 25 + 2516 + 4819 + 12 @@ -8903,7 +9068,7 @@ 1 2 - 131549 + 130958 @@ -8919,7 +9084,7 @@ 1 2 - 131549 + 130958 @@ -8929,15 +9094,15 @@ ruby_class_def - 16778 + 16841 id - 16778 + 16841 name - 16778 + 16841 @@ -8951,7 +9116,7 @@ 1 2 - 16778 + 16841 @@ -8967,7 +9132,7 @@ 1 2 - 16778 + 16841 @@ -8977,15 +9142,15 @@ ruby_class_superclass - 13262 + 13314 ruby_class - 13262 + 13314 superclass - 13262 + 13314 @@ -8999,7 +9164,7 @@ 1 2 - 13262 + 13314 @@ -9015,7 +9180,55 @@ 1 2 - 13262 + 13314 + + + + + + + + + ruby_complex_def + 53 + + + id + 53 + + + child + 53 + + + + + id + child + + + 12 + + + 1 + 2 + 53 + + + + + + + child + id + + + 12 + + + 1 + 2 + 53 @@ -9025,23 +9238,23 @@ ruby_conditional_def - 3556 + 3464 id - 3556 + 3464 alternative - 3556 + 3464 condition - 3556 + 3464 consequence - 3556 + 3464 @@ -9055,7 +9268,7 @@ 1 2 - 3556 + 3464 @@ -9071,7 +9284,7 @@ 1 2 - 3556 + 3464 @@ -9087,7 +9300,7 @@ 1 2 - 3556 + 3464 @@ -9103,7 +9316,7 @@ 1 2 - 3556 + 3464 @@ -9119,7 +9332,7 @@ 1 2 - 3556 + 3464 @@ -9135,7 +9348,7 @@ 1 2 - 3556 + 3464 @@ -9151,7 +9364,7 @@ 1 2 - 3556 + 3464 @@ -9167,7 +9380,7 @@ 1 2 - 3556 + 3464 @@ -9183,7 +9396,7 @@ 1 2 - 3556 + 3464 @@ -9199,7 +9412,7 @@ 1 2 - 3556 + 3464 @@ -9215,7 +9428,7 @@ 1 2 - 3556 + 3464 @@ -9231,7 +9444,7 @@ 1 2 - 3556 + 3464 @@ -9241,11 +9454,11 @@ ruby_delimited_symbol_child - 1679 + 1739 ruby_delimited_symbol - 1216 + 1257 index @@ -9253,7 +9466,7 @@ child - 1679 + 1739 @@ -9267,12 +9480,12 @@ 1 2 - 916 + 939 2 3 - 226 + 245 3 @@ -9293,12 +9506,12 @@ 1 2 - 916 + 939 2 3 - 226 + 245 3 @@ -9347,13 +9560,13 @@ 3 - 95 - 96 + 101 + 102 3 - 386 - 387 + 399 + 400 3 @@ -9398,13 +9611,13 @@ 3 - 95 - 96 + 101 + 102 3 - 386 - 387 + 399 + 400 3 @@ -9421,7 +9634,7 @@ 1 2 - 1679 + 1739 @@ -9437,7 +9650,7 @@ 1 2 - 1679 + 1739 @@ -9447,11 +9660,11 @@ ruby_delimited_symbol_def - 1216 + 1257 id - 1216 + 1257 @@ -9822,19 +10035,19 @@ ruby_do_block_child - 392587 + 395009 ruby_do_block - 136404 + 137279 index - 931 + 935 child - 392587 + 395009 @@ -9848,32 +10061,32 @@ 1 2 - 47663 + 48036 2 3 - 36523 + 36712 3 4 - 21515 + 21583 4 5 - 10389 + 10506 5 7 - 10518 + 10583 7 73 - 9793 + 9856 @@ -9889,32 +10102,32 @@ 1 2 - 47663 + 48036 2 3 - 36523 + 36712 3 4 - 21515 + 21583 4 5 - 10389 + 10506 5 7 - 10518 + 10583 7 73 - 9793 + 9856 @@ -9935,7 +10148,7 @@ 2 3 - 219 + 220 4 @@ -9973,18 +10186,18 @@ 77 - 174 + 175 592 77 - 757 - 6860 + 759 + 6873 77 - 10543 - 10544 + 10571 + 10572 12 @@ -10006,7 +10219,7 @@ 2 3 - 219 + 220 4 @@ -10044,18 +10257,18 @@ 77 - 174 + 175 592 77 - 757 - 6860 + 759 + 6873 77 - 10543 - 10544 + 10571 + 10572 12 @@ -10072,7 +10285,7 @@ 1 2 - 392587 + 395009 @@ -10088,7 +10301,7 @@ 1 2 - 392587 + 395009 @@ -10098,26 +10311,26 @@ ruby_do_block_def - 136559 + 137435 id - 136559 + 137435 ruby_do_block_parameters - 15052 + 15073 ruby_do_block - 15052 + 15073 parameters - 15052 + 15073 @@ -10131,7 +10344,7 @@ 1 2 - 15052 + 15073 @@ -10147,7 +10360,7 @@ 1 2 - 15052 + 15073 @@ -10157,11 +10370,11 @@ ruby_do_child - 9209 + 9177 ruby_do - 1598 + 1588 index @@ -10169,7 +10382,7 @@ child - 9209 + 9177 @@ -10183,17 +10396,17 @@ 1 2 - 329 + 324 2 3 - 274 + 273 3 4 - 193 + 191 4 @@ -10203,7 +10416,7 @@ 5 7 - 105 + 104 7 @@ -10218,7 +10431,7 @@ 9 14 - 118 + 117 14 @@ -10244,17 +10457,17 @@ 1 2 - 329 + 324 2 3 - 274 + 273 3 4 - 193 + 191 4 @@ -10264,7 +10477,7 @@ 5 7 - 105 + 104 7 @@ -10279,7 +10492,7 @@ 9 14 - 118 + 117 14 @@ -10329,7 +10542,7 @@ 112 - 1599 + 1589 15 @@ -10370,7 +10583,7 @@ 112 - 1599 + 1589 15 @@ -10387,7 +10600,7 @@ 1 2 - 9209 + 9177 @@ -10403,7 +10616,7 @@ 1 2 - 9209 + 9177 @@ -10413,30 +10626,30 @@ ruby_do_def - 1621 + 1610 id - 1621 + 1610 ruby_element_reference_child - 82444 + 82398 ruby_element_reference - 82275 + 82228 index - 6 + 5 child - 82444 + 82398 @@ -10450,7 +10663,7 @@ 1 2 - 82105 + 82059 2 @@ -10471,7 +10684,7 @@ 1 2 - 82105 + 82059 2 @@ -10490,14 +10703,14 @@ 12 - 56 - 57 - 3 + 57 + 58 + 2 - 27139 - 27140 - 3 + 27674 + 27675 + 2 @@ -10511,14 +10724,14 @@ 12 - 56 - 57 - 3 + 57 + 58 + 2 - 27139 - 27140 - 3 + 27674 + 27675 + 2 @@ -10534,7 +10747,7 @@ 1 2 - 82444 + 82398 @@ -10550,7 +10763,7 @@ 1 2 - 82444 + 82398 @@ -10560,15 +10773,15 @@ ruby_element_reference_def - 82281 + 82234 id - 82281 + 82234 object - 82281 + 82234 @@ -10582,7 +10795,7 @@ 1 2 - 82281 + 82234 @@ -10598,7 +10811,7 @@ 1 2 - 82281 + 82234 @@ -10608,11 +10821,11 @@ ruby_else_child - 8817 + 8802 ruby_else - 6937 + 6923 index @@ -10620,7 +10833,7 @@ child - 8817 + 8802 @@ -10634,12 +10847,12 @@ 1 2 - 5847 + 5833 2 3 - 686 + 687 3 @@ -10660,12 +10873,12 @@ 1 2 - 5847 + 5833 2 3 - 686 + 687 3 @@ -10719,8 +10932,8 @@ 3 - 56 - 57 + 55 + 56 3 @@ -10734,8 +10947,8 @@ 3 - 2202 - 2203 + 2197 + 2198 3 @@ -10785,8 +10998,8 @@ 3 - 56 - 57 + 55 + 56 3 @@ -10800,8 +11013,8 @@ 3 - 2202 - 2203 + 2197 + 2198 3 @@ -10818,7 +11031,7 @@ 1 2 - 8817 + 8802 @@ -10834,7 +11047,7 @@ 1 2 - 8817 + 8802 @@ -10844,26 +11057,26 @@ ruby_else_def - 6946 + 6933 id - 6946 + 6933 ruby_elsif_alternative - 897 + 903 ruby_elsif - 897 + 903 alternative - 897 + 903 @@ -10877,7 +11090,7 @@ 1 2 - 897 + 903 @@ -10893,7 +11106,7 @@ 1 2 - 897 + 903 @@ -10903,15 +11116,15 @@ ruby_elsif_consequence - 1603 + 1589 ruby_elsif - 1603 + 1589 consequence - 1603 + 1589 @@ -10925,7 +11138,7 @@ 1 2 - 1603 + 1589 @@ -10941,7 +11154,7 @@ 1 2 - 1603 + 1589 @@ -10951,15 +11164,15 @@ ruby_elsif_def - 1606 + 1595 id - 1606 + 1595 condition - 1606 + 1595 @@ -10973,7 +11186,7 @@ 1 2 - 1606 + 1595 @@ -10989,7 +11202,7 @@ 1 2 - 1606 + 1595 @@ -11186,11 +11399,11 @@ ruby_ensure_child - 5078 + 4834 ruby_ensure - 3786 + 3718 index @@ -11198,7 +11411,7 @@ child - 5078 + 4834 @@ -11212,22 +11425,17 @@ 1 2 - 2958 + 2956 2 3 - 535 + 516 3 - 9 - 286 - - - 16 17 - 6 + 245 @@ -11243,22 +11451,17 @@ 1 2 - 2958 + 2956 2 3 - 535 + 516 3 - 9 - 286 - - - 16 17 - 6 + 245 @@ -11272,38 +11475,38 @@ 12 - 2 - 3 + 1 + 2 25 - 5 - 6 + 3 + 4 6 - 6 - 7 + 4 + 5 6 - 16 - 17 + 12 + 13 3 - 93 - 94 + 78 + 79 3 - 263 - 264 + 242 + 243 3 - 1202 - 1203 + 1180 + 1181 3 @@ -11318,38 +11521,38 @@ 12 - 2 - 3 + 1 + 2 25 - 5 - 6 + 3 + 4 6 - 6 - 7 + 4 + 5 6 - 16 - 17 + 12 + 13 3 - 93 - 94 + 78 + 79 3 - 263 - 264 + 242 + 243 3 - 1202 - 1203 + 1180 + 1181 3 @@ -11366,7 +11569,7 @@ 1 2 - 5078 + 4834 @@ -11382,7 +11585,7 @@ 1 2 - 5078 + 4834 @@ -11392,26 +11595,26 @@ ruby_ensure_def - 3786 + 3718 id - 3786 + 3718 ruby_exception_variable_def - 1021 + 1001 id - 1021 + 1001 child - 1021 + 1001 @@ -11425,7 +11628,7 @@ 1 2 - 1021 + 1001 @@ -11441,7 +11644,7 @@ 1 2 - 1021 + 1001 @@ -11451,11 +11654,11 @@ ruby_exceptions_child - 1852 + 1849 ruby_exceptions - 1641 + 1639 index @@ -11463,7 +11666,7 @@ child - 1852 + 1849 @@ -11477,12 +11680,12 @@ 1 2 - 1498 + 1497 2 4 - 130 + 129 4 @@ -11503,12 +11706,12 @@ 1 2 - 1498 + 1497 2 4 - 130 + 129 4 @@ -11557,13 +11760,13 @@ 1 - 143 - 144 + 142 + 143 1 - 1641 - 1642 + 1639 + 1640 1 @@ -11608,13 +11811,13 @@ 1 - 143 - 144 + 142 + 143 1 - 1641 - 1642 + 1639 + 1640 1 @@ -11631,7 +11834,7 @@ 1 2 - 1852 + 1849 @@ -11647,7 +11850,7 @@ 1 2 - 1852 + 1849 @@ -11657,11 +11860,11 @@ ruby_exceptions_def - 1641 + 1639 id - 1641 + 1639 @@ -11690,7 +11893,7 @@ 1 2 - 3 + 2 @@ -11776,7 +11979,7 @@ 1 2 - 3 + 2 @@ -11792,7 +11995,7 @@ 1 2 - 3 + 2 @@ -11824,7 +12027,7 @@ 1 2 - 3 + 2 @@ -11840,7 +12043,7 @@ 1 2 - 3 + 2 @@ -11861,23 +12064,23 @@ ruby_for_def - 163 + 162 id - 163 + 162 body - 163 + 162 pattern - 163 + 162 value - 163 + 162 @@ -11891,7 +12094,7 @@ 1 2 - 163 + 162 @@ -11907,7 +12110,7 @@ 1 2 - 163 + 162 @@ -11923,7 +12126,7 @@ 1 2 - 163 + 162 @@ -11939,7 +12142,7 @@ 1 2 - 163 + 162 @@ -11955,7 +12158,7 @@ 1 2 - 163 + 162 @@ -11971,7 +12174,7 @@ 1 2 - 163 + 162 @@ -11987,7 +12190,7 @@ 1 2 - 163 + 162 @@ -12003,7 +12206,7 @@ 1 2 - 163 + 162 @@ -12019,7 +12222,7 @@ 1 2 - 163 + 162 @@ -12035,7 +12238,7 @@ 1 2 - 163 + 162 @@ -12051,7 +12254,7 @@ 1 2 - 163 + 162 @@ -12067,7 +12270,7 @@ 1 2 - 163 + 162 @@ -12077,19 +12280,19 @@ ruby_hash_child - 88753 + 88983 ruby_hash - 35630 + 35712 index - 1384 + 1389 child - 88753 + 88983 @@ -12103,27 +12306,27 @@ 1 2 - 14762 + 14778 2 3 - 9897 + 9960 3 4 - 3971 + 3960 4 5 - 4140 + 4142 5 19 - 2678 + 2688 19 @@ -12144,27 +12347,27 @@ 1 2 - 14762 + 14778 2 3 - 9897 + 9960 3 4 - 3971 + 3960 4 5 - 4140 + 4142 5 19 - 2678 + 2688 19 @@ -12185,28 +12388,33 @@ 1 2 - 918 + 922 3 - 5 - 116 + 4 + 103 5 - 15 + 11 116 - 15 - 58 + 14 + 51 116 - 71 - 2755 + 57 + 1613 116 + + 2750 + 2751 + 12 + @@ -12221,28 +12429,33 @@ 1 2 - 918 + 922 3 - 5 - 116 + 4 + 103 5 - 15 + 11 116 - 15 - 58 + 14 + 51 116 - 71 - 2755 + 57 + 1613 116 + + 2750 + 2751 + 12 + @@ -12257,7 +12470,7 @@ 1 2 - 88753 + 88983 @@ -12273,7 +12486,7 @@ 1 2 - 88753 + 88983 @@ -12283,11 +12496,11 @@ ruby_hash_def - 39344 + 39413 id - 39344 + 39413 @@ -12360,7 +12573,7 @@ 1 2 - 3 + 2 @@ -12376,7 +12589,7 @@ 1 2 - 3 + 2 @@ -12408,7 +12621,7 @@ 1 2 - 3 + 2 @@ -12424,7 +12637,7 @@ 1 2 - 3 + 2 @@ -12445,15 +12658,15 @@ ruby_hash_splat_argument_def - 1813 + 1856 id - 1813 + 1856 child - 1813 + 1856 @@ -12467,7 +12680,7 @@ 1 2 - 1813 + 1856 @@ -12483,7 +12696,7 @@ 1 2 - 1813 + 1856 @@ -12493,26 +12706,26 @@ ruby_hash_splat_parameter_def - 1351 + 1355 id - 1351 + 1355 ruby_hash_splat_parameter_name - 1130 + 1134 ruby_hash_splat_parameter - 1130 + 1134 name - 1130 + 1134 @@ -12526,7 +12739,7 @@ 1 2 - 1130 + 1134 @@ -12542,7 +12755,7 @@ 1 2 - 1130 + 1134 @@ -12552,19 +12765,19 @@ ruby_heredoc_body_child - 25086 + 25318 ruby_heredoc_body - 5332 + 5363 index - 218 + 264 child - 25086 + 25318 @@ -12578,27 +12791,27 @@ 2 3 - 2907 + 2929 4 5 - 682 + 692 5 6 - 3 + 2 6 7 - 788 + 781 7 9 - 339 + 341 10 @@ -12607,8 +12820,8 @@ 16 - 73 - 190 + 90 + 193 @@ -12624,27 +12837,27 @@ 2 3 - 2907 + 2929 4 5 - 682 + 692 5 6 - 3 + 2 6 7 - 788 + 781 7 9 - 339 + 341 10 @@ -12653,8 +12866,8 @@ 16 - 73 - 190 + 90 + 193 @@ -12670,57 +12883,42 @@ 1 2 - 57 + 50 2 3 - 27 + 83 4 - 5 - 12 - - - 5 - 8 - 15 + 6 + 23 8 - 9 - 9 + 12 + 23 - 10 - 13 - 18 + 12 + 26 + 23 - 15 - 25 - 18 + 30 + 94 + 20 - 29 - 64 - 18 + 96 + 323 + 20 - 91 - 203 - 18 - - - 309 - 801 - 18 - - - 1759 - 1760 - 6 + 585 + 1806 + 17 @@ -12736,57 +12934,42 @@ 1 2 - 57 + 50 2 3 - 27 + 83 4 - 5 - 12 - - - 5 - 8 - 15 + 6 + 23 8 - 9 - 9 + 12 + 23 - 10 - 13 - 18 + 12 + 26 + 23 - 15 - 25 - 18 + 30 + 94 + 20 - 29 - 64 - 18 + 96 + 323 + 20 - 91 - 203 - 18 - - - 309 - 801 - 18 - - - 1759 - 1760 - 6 + 585 + 1806 + 17 @@ -12802,7 +12985,7 @@ 1 2 - 25086 + 25318 @@ -12818,7 +13001,7 @@ 1 2 - 25086 + 25318 @@ -12828,26 +13011,26 @@ ruby_heredoc_body_def - 5577 + 5575 id - 5577 + 5575 ruby_if_alternative - 6461 + 6454 ruby_if - 6461 + 6454 alternative - 6461 + 6454 @@ -12861,7 +13044,7 @@ 1 2 - 6461 + 6454 @@ -12877,7 +13060,7 @@ 1 2 - 6461 + 6454 @@ -12887,15 +13070,15 @@ ruby_if_consequence - 18444 + 18324 ruby_if - 18444 + 18324 consequence - 18444 + 18324 @@ -12909,7 +13092,7 @@ 1 2 - 18444 + 18324 @@ -12925,7 +13108,7 @@ 1 2 - 18444 + 18324 @@ -12935,15 +13118,15 @@ ruby_if_def - 18504 + 18392 id - 18504 + 18392 condition - 18504 + 18392 @@ -12957,7 +13140,7 @@ 1 2 - 18504 + 18392 @@ -12973,7 +13156,7 @@ 1 2 - 18504 + 18392 @@ -13005,7 +13188,7 @@ 1 2 - 3 + 2 @@ -13025,19 +13208,19 @@ ruby_if_modifier_def - 13763 + 13620 id - 13763 + 13620 body - 13763 + 13620 condition - 13763 + 13620 @@ -13051,7 +13234,7 @@ 1 2 - 13763 + 13620 @@ -13067,7 +13250,7 @@ 1 2 - 13763 + 13620 @@ -13083,7 +13266,7 @@ 1 2 - 13763 + 13620 @@ -13099,7 +13282,7 @@ 1 2 - 13763 + 13620 @@ -13115,7 +13298,7 @@ 1 2 - 13763 + 13620 @@ -13131,7 +13314,7 @@ 1 2 - 13763 + 13620 @@ -13141,15 +13324,15 @@ ruby_in_clause_body - 2 + 0 ruby_in_clause - 2 + 0 body - 2 + 0 @@ -13189,15 +13372,15 @@ ruby_in_clause_def - 2 + 0 id - 2 + 0 pattern - 2 + 0 @@ -13223,13 +13406,7 @@ 12 - - - 1 - 2 - 2 - - + @@ -13259,7 +13436,7 @@ 1 2 - 3 + 2 @@ -13275,7 +13452,7 @@ 1 2 - 3 + 2 @@ -13285,15 +13462,15 @@ ruby_in_def - 163 + 162 id - 163 + 162 child - 163 + 162 @@ -13307,7 +13484,7 @@ 1 2 - 163 + 162 @@ -13323,7 +13500,7 @@ 1 2 - 163 + 162 @@ -13333,19 +13510,19 @@ ruby_interpolation_child - 38383 + 38208 ruby_interpolation - 38383 + 38208 index - 3 + 2 child - 38383 + 38208 @@ -13359,7 +13536,7 @@ 1 2 - 38383 + 38208 @@ -13375,7 +13552,7 @@ 1 2 - 38383 + 38208 @@ -13389,9 +13566,9 @@ 12 - 12661 - 12662 - 3 + 12859 + 12860 + 2 @@ -13405,9 +13582,9 @@ 12 - 12661 - 12662 - 3 + 12859 + 12860 + 2 @@ -13423,7 +13600,7 @@ 1 2 - 38383 + 38208 @@ -13439,7 +13616,7 @@ 1 2 - 38383 + 38208 @@ -13449,26 +13626,26 @@ ruby_interpolation_def - 38383 + 38208 id - 38383 + 38208 ruby_keyword_parameter_def - 3777 + 3794 id - 3777 + 3794 name - 3777 + 3794 @@ -13482,7 +13659,7 @@ 1 2 - 3777 + 3794 @@ -13498,7 +13675,7 @@ 1 2 - 3777 + 3794 @@ -13508,15 +13685,15 @@ ruby_keyword_parameter_value - 2832 + 2874 ruby_keyword_parameter - 2832 + 2874 value - 2832 + 2874 @@ -13530,7 +13707,7 @@ 1 2 - 2832 + 2874 @@ -13546,7 +13723,7 @@ 1 2 - 2832 + 2874 @@ -13578,7 +13755,7 @@ 1 2 - 3 + 2 @@ -13620,7 +13797,7 @@ 1 2 - 3 + 2 @@ -13636,7 +13813,7 @@ 1 2 - 3 + 2 @@ -13646,15 +13823,15 @@ ruby_lambda_def - 7499 + 7472 id - 7499 + 7472 body - 7499 + 7472 @@ -13668,7 +13845,7 @@ 1 2 - 7499 + 7472 @@ -13684,7 +13861,7 @@ 1 2 - 7499 + 7472 @@ -13694,15 +13871,15 @@ ruby_lambda_parameters - 1659 + 1664 ruby_lambda - 1659 + 1664 parameters - 1659 + 1664 @@ -13716,7 +13893,7 @@ 1 2 - 1659 + 1664 @@ -13732,7 +13909,7 @@ 1 2 - 1659 + 1664 @@ -13742,11 +13919,11 @@ ruby_lambda_parameters_child - 1898 + 1905 ruby_lambda_parameters - 1650 + 1655 index @@ -13754,7 +13931,7 @@ child - 1898 + 1905 @@ -13768,12 +13945,12 @@ 1 2 - 1469 + 1472 2 3 - 142 + 144 3 @@ -13794,12 +13971,12 @@ 1 2 - 1469 + 1472 2 3 - 142 + 144 3 @@ -13843,13 +14020,13 @@ 1 - 181 - 182 + 183 + 184 1 - 1650 - 1651 + 1655 + 1656 1 @@ -13889,13 +14066,13 @@ 1 - 181 - 182 + 183 + 184 1 - 1650 - 1651 + 1655 + 1656 1 @@ -13912,7 +14089,7 @@ 1 2 - 1898 + 1905 @@ -13928,7 +14105,7 @@ 1 2 - 1898 + 1905 @@ -13938,22 +14115,22 @@ ruby_lambda_parameters_def - 1659 + 1664 id - 1659 + 1664 ruby_left_assignment_list_child - 6390 + 6358 ruby_left_assignment_list - 2887 + 2873 index @@ -13961,7 +14138,7 @@ child - 6390 + 6358 @@ -13975,17 +14152,17 @@ 1 2 - 359 + 360 2 3 - 1873 + 1861 3 4 - 492 + 489 4 @@ -14006,17 +14183,17 @@ 1 2 - 359 + 360 2 3 - 1873 + 1861 3 4 - 492 + 489 4 @@ -14080,18 +14257,18 @@ 1 - 655 - 656 + 652 + 653 1 - 2528 - 2529 + 2513 + 2514 1 - 2887 - 2888 + 2873 + 2874 1 @@ -14151,18 +14328,18 @@ 1 - 655 - 656 + 652 + 653 1 - 2528 - 2529 + 2513 + 2514 1 - 2887 - 2888 + 2873 + 2874 1 @@ -14179,7 +14356,7 @@ 1 2 - 6390 + 6358 @@ -14195,7 +14372,7 @@ 1 2 - 6390 + 6358 @@ -14205,22 +14382,22 @@ ruby_left_assignment_list_def - 2887 + 2873 id - 2887 + 2873 ruby_method_child - 265363 + 264218 ruby_method - 97610 + 97351 index @@ -14228,7 +14405,7 @@ child - 265363 + 264218 @@ -14242,32 +14419,32 @@ 1 2 - 43881 + 43682 2 3 - 17963 + 18007 3 4 - 12762 + 12772 4 5 - 7819 + 7790 5 7 - 8115 + 8159 7 77 - 7069 + 6939 @@ -14283,32 +14460,32 @@ 1 2 - 43881 + 43682 2 3 - 17963 + 18007 3 4 - 12762 + 12772 4 5 - 7819 + 7790 5 7 - 8115 + 8159 7 77 - 7069 + 6939 @@ -14344,41 +14521,41 @@ 6 7 - 25 - - - 8 - 12 - 12 - - - 13 - 19 18 - 20 - 38 + 7 + 13 18 - 46 - 116 + 14 + 20 18 - 151 - 407 + 21 + 41 18 - 521 - 2245 + 49 + 115 18 - 3247 - 30985 + 150 + 400 + 18 + + + 511 + 2203 + 18 + + + 3217 + 30892 18 @@ -14415,41 +14592,41 @@ 6 7 - 25 - - - 8 - 12 - 12 - - - 13 - 19 18 - 20 - 38 + 7 + 13 18 - 46 - 116 + 14 + 20 18 - 151 - 407 + 21 + 41 18 - 521 - 2245 + 49 + 115 18 - 3247 - 30985 + 150 + 400 + 18 + + + 511 + 2203 + 18 + + + 3217 + 30892 18 @@ -14466,7 +14643,7 @@ 1 2 - 265363 + 264218 @@ -14482,7 +14659,7 @@ 1 2 - 265363 + 264218 @@ -14492,15 +14669,15 @@ ruby_method_def - 98643 + 98356 id - 98643 + 98356 name - 98643 + 98356 @@ -14514,7 +14691,7 @@ 1 2 - 98643 + 98356 @@ -14530,7 +14707,7 @@ 1 2 - 98643 + 98356 @@ -14540,15 +14717,15 @@ ruby_method_parameters - 27323 + 27238 ruby_method - 27323 + 27238 parameters - 27323 + 27238 @@ -14562,7 +14739,7 @@ 1 2 - 27323 + 27238 @@ -14578,7 +14755,7 @@ 1 2 - 27323 + 27238 @@ -14588,11 +14765,11 @@ ruby_method_parameters_child - 47661 + 47287 ruby_method_parameters - 28778 + 28643 index @@ -14600,7 +14777,7 @@ child - 47661 + 47287 @@ -14614,22 +14791,22 @@ 1 2 - 17326 + 17310 2 3 - 7059 + 7021 3 4 - 2740 + 2678 4 12 - 1650 + 1632 @@ -14645,22 +14822,22 @@ 1 2 - 17326 + 17310 2 3 - 7059 + 7021 3 4 - 2740 + 2678 4 12 - 1650 + 1632 @@ -14694,38 +14871,38 @@ 3 - 49 - 50 + 48 + 49 3 - 116 - 117 + 115 + 116 3 - 231 - 232 + 226 + 227 3 - 524 - 525 + 518 + 519 3 - 1394 - 1395 + 1368 + 1369 3 - 3635 - 3636 + 3596 + 3597 3 - 9135 - 9136 + 9089 + 9090 3 @@ -14760,38 +14937,38 @@ 3 - 49 - 50 + 48 + 49 3 - 116 - 117 + 115 + 116 3 - 231 - 232 + 226 + 227 3 - 524 - 525 + 518 + 519 3 - 1394 - 1395 + 1368 + 1369 3 - 3635 - 3636 + 3596 + 3597 3 - 9135 - 9136 + 9089 + 9090 3 @@ -14808,7 +14985,7 @@ 1 2 - 47661 + 47287 @@ -14824,7 +15001,7 @@ 1 2 - 47661 + 47287 @@ -14834,22 +15011,22 @@ ruby_method_parameters_def - 28992 + 28861 id - 28992 + 28861 ruby_module_child - 31229 + 31303 ruby_module - 10544 + 10513 index @@ -14857,7 +15034,7 @@ child - 31229 + 31303 @@ -14871,27 +15048,27 @@ 1 2 - 7466 + 7443 2 3 - 885 + 863 3 5 - 762 + 772 5 - 11 - 853 + 10 + 794 - 11 + 10 126 - 576 + 639 @@ -14907,27 +15084,27 @@ 1 2 - 7466 + 7443 2 3 - 885 + 863 3 5 - 762 + 772 5 - 11 - 853 + 10 + 794 - 11 + 10 126 - 576 + 639 @@ -14943,26 +15120,26 @@ 1 2 - 37 + 31 2 3 - 31 + 37 3 4 - 3 + 9 4 5 - 78 + 72 5 - 7 + 8 31 @@ -14972,32 +15149,32 @@ 10 - 16 + 17 34 - 16 + 17 25 34 - 28 - 46 + 27 + 49 31 - 51 - 108 + 52 + 109 31 - 123 - 374 + 122 + 376 31 - 454 - 3348 + 455 + 3337 15 @@ -15014,26 +15191,26 @@ 1 2 - 37 + 31 2 3 - 31 + 37 3 4 - 3 + 9 4 5 - 78 + 72 5 - 7 + 8 31 @@ -15043,32 +15220,32 @@ 10 - 16 + 17 34 - 16 + 17 25 34 - 28 - 46 + 27 + 49 31 - 51 - 108 + 52 + 109 31 - 123 - 374 + 122 + 376 31 - 454 - 3348 + 455 + 3337 15 @@ -15085,7 +15262,7 @@ 1 2 - 31229 + 31303 @@ -15101,7 +15278,7 @@ 1 2 - 31229 + 31303 @@ -15111,15 +15288,15 @@ ruby_module_def - 21140 + 21557 id - 21140 + 21557 name - 21140 + 21557 @@ -15133,7 +15310,7 @@ 1 2 - 21140 + 21557 @@ -15149,7 +15326,7 @@ 1 2 - 21140 + 21557 @@ -15207,34 +15384,34 @@ ruby_next_def - 2070 + 2005 id - 2070 + 2005 ruby_operator_assignment_def - 6618 + 6596 id - 6618 + 6596 left - 6618 + 6596 operator - 18 + 17 right - 6618 + 6596 @@ -15248,7 +15425,7 @@ 1 2 - 6618 + 6596 @@ -15264,7 +15441,7 @@ 1 2 - 6618 + 6596 @@ -15280,7 +15457,7 @@ 1 2 - 6618 + 6596 @@ -15296,7 +15473,7 @@ 1 2 - 6618 + 6596 @@ -15312,7 +15489,7 @@ 1 2 - 6618 + 6596 @@ -15328,7 +15505,7 @@ 1 2 - 6618 + 6596 @@ -15344,32 +15521,32 @@ 1 2 - 3 + 2 5 6 - 3 + 2 9 10 - 3 + 2 - 60 - 61 - 3 + 61 + 62 + 2 - 578 - 579 - 3 + 592 + 593 + 2 - 1530 - 1531 - 3 + 1552 + 1553 + 2 @@ -15385,32 +15562,32 @@ 1 2 - 3 + 2 5 6 - 3 + 2 9 10 - 3 + 2 - 60 - 61 - 3 + 61 + 62 + 2 - 578 - 579 - 3 + 592 + 593 + 2 - 1530 - 1531 - 3 + 1552 + 1553 + 2 @@ -15426,32 +15603,32 @@ 1 2 - 3 + 2 5 6 - 3 + 2 9 10 - 3 + 2 - 60 - 61 - 3 + 61 + 62 + 2 - 578 - 579 - 3 + 592 + 593 + 2 - 1530 - 1531 - 3 + 1552 + 1553 + 2 @@ -15467,7 +15644,7 @@ 1 2 - 6618 + 6596 @@ -15483,7 +15660,7 @@ 1 2 - 6618 + 6596 @@ -15499,7 +15676,7 @@ 1 2 - 6618 + 6596 @@ -15509,19 +15686,19 @@ ruby_optional_parameter_def - 6527 + 6435 id - 6527 + 6435 name - 6527 + 6435 value - 6527 + 6435 @@ -15535,7 +15712,7 @@ 1 2 - 6527 + 6435 @@ -15551,7 +15728,7 @@ 1 2 - 6527 + 6435 @@ -15567,7 +15744,7 @@ 1 2 - 6527 + 6435 @@ -15583,7 +15760,7 @@ 1 2 - 6527 + 6435 @@ -15599,7 +15776,7 @@ 1 2 - 6527 + 6435 @@ -15615,7 +15792,7 @@ 1 2 - 6527 + 6435 @@ -15625,15 +15802,15 @@ ruby_pair_def - 235172 + 235158 id - 235172 + 235158 key__ - 235172 + 235158 @@ -15647,7 +15824,7 @@ 1 2 - 235172 + 235158 @@ -15663,7 +15840,7 @@ 1 2 - 235172 + 235158 @@ -15673,15 +15850,15 @@ ruby_pair_value - 235172 + 235158 ruby_pair - 235172 + 235158 value - 235172 + 235158 @@ -15695,7 +15872,7 @@ 1 2 - 235172 + 235158 @@ -15711,7 +15888,7 @@ 1 2 - 235172 + 235158 @@ -15743,7 +15920,7 @@ 1 2 - 3 + 2 @@ -15763,11 +15940,11 @@ ruby_parenthesized_statements_child - 10178 + 10272 ruby_parenthesized_statements - 10114 + 10208 index @@ -15775,7 +15952,7 @@ child - 10178 + 10272 @@ -15789,7 +15966,7 @@ 1 2 - 10058 + 10152 2 @@ -15810,7 +15987,7 @@ 1 2 - 10058 + 10152 2 @@ -15844,8 +16021,8 @@ 1 - 10114 - 10115 + 10208 + 10209 1 @@ -15875,8 +16052,8 @@ 1 - 10114 - 10115 + 10208 + 10209 1 @@ -15893,7 +16070,7 @@ 1 2 - 10178 + 10272 @@ -15909,7 +16086,7 @@ 1 2 - 10178 + 10272 @@ -15919,26 +16096,26 @@ ruby_parenthesized_statements_def - 10153 + 10247 id - 10153 + 10247 ruby_pattern_def - 3878 + 3895 id - 3878 + 3895 child - 3878 + 3895 @@ -15952,7 +16129,7 @@ 1 2 - 3878 + 3895 @@ -15968,7 +16145,7 @@ 1 2 - 3878 + 3895 @@ -15978,19 +16155,19 @@ ruby_program_child - 33094 + 33147 ruby_program - 10452 + 10456 index - 239 + 236 child - 33094 + 33147 @@ -16004,32 +16181,32 @@ 1 2 - 3865 + 3857 2 3 - 2526 + 2527 3 4 - 1650 + 1660 4 5 - 778 + 791 5 8 - 916 + 910 8 - 77 - 715 + 76 + 709 @@ -16045,32 +16222,32 @@ 1 2 - 3865 + 3857 2 3 - 2526 + 2527 3 4 - 1650 + 1660 4 5 - 778 + 791 5 8 - 916 + 910 8 - 77 - 715 + 76 + 709 @@ -16086,7 +16263,7 @@ 1 2 - 53 + 50 2 @@ -16105,27 +16282,27 @@ 15 - 22 + 23 18 - 25 + 26 37 18 38 - 62 + 63 18 - 67 - 138 + 68 + 139 18 - 161 - 519 + 157 + 515 18 @@ -16147,7 +16324,7 @@ 1 2 - 53 + 50 2 @@ -16166,27 +16343,27 @@ 15 - 22 + 23 18 - 25 + 26 37 18 38 - 62 + 63 18 - 67 - 138 + 68 + 139 18 - 161 - 519 + 157 + 515 18 @@ -16208,7 +16385,7 @@ 1 2 - 33094 + 33147 @@ -16224,7 +16401,7 @@ 1 2 - 33094 + 33147 @@ -16234,26 +16411,26 @@ ruby_program_def - 16935 + 17142 id - 16935 + 17142 ruby_range_begin - 4241 + 3997 ruby_range - 4241 + 3997 begin - 4241 + 3997 @@ -16267,7 +16444,7 @@ 1 2 - 4241 + 3997 @@ -16283,7 +16460,7 @@ 1 2 - 4241 + 3997 @@ -16293,11 +16470,11 @@ ruby_range_def - 4294 + 4187 id - 4294 + 4187 operator @@ -16315,7 +16492,7 @@ 1 2 - 4294 + 4187 @@ -16329,13 +16506,13 @@ 12 - 1544 - 1545 + 1356 + 1357 1 - 2750 - 2751 + 2831 + 2832 1 @@ -16346,15 +16523,15 @@ ruby_range_end - 3671 + 4070 ruby_range - 3671 + 4070 end - 3671 + 4070 @@ -16368,7 +16545,7 @@ 1 2 - 3671 + 4070 @@ -16384,7 +16561,7 @@ 1 2 - 3671 + 4070 @@ -16464,7 +16641,7 @@ 1 2 - 3 + 2 @@ -16480,7 +16657,7 @@ 1 2 - 3 + 2 @@ -16501,19 +16678,19 @@ ruby_regex_child - 42882 + 43301 ruby_regex - 12812 + 12839 index - 135 + 154 child - 42882 + 43301 @@ -16532,37 +16709,37 @@ 2 3 - 721 + 696 3 4 - 1688 + 1723 4 5 - 500 + 466 5 6 - 1086 + 1087 6 8 - 982 + 1002 8 - 16 - 1023 + 15 + 986 - 16 - 44 - 229 + 15 + 50 + 299 @@ -16583,37 +16760,37 @@ 2 3 - 721 + 696 3 4 - 1688 + 1723 4 5 - 500 + 466 5 6 - 1086 + 1087 6 8 - 982 + 1002 8 - 16 - 1023 + 15 + 986 - 16 - 44 - 229 + 15 + 50 + 299 @@ -16627,85 +16804,70 @@ 12 - 2 - 3 - 12 + 1 + 2 + 18 4 5 + 12 + + + 6 + 7 3 - - 5 - 6 - 9 - 7 - 10 - 9 + 8 + 12 - 10 + 8 15 - 6 + 12 15 - 16 - 6 + 18 + 12 - 17 - 19 - 9 - - - 20 + 18 22 - 6 + 9 22 - 28 - 9 + 30 + 12 - 29 - 37 - 9 + 31 + 73 + 12 - 54 - 95 - 9 - - - 106 + 95 165 - 9 + 12 - 227 - 336 - 9 + 230 + 409 + 12 - 398 - 711 - 9 + 645 + 1220 + 12 - 1055 - 1751 + 1766 + 4075 9 - - 1979 - 4068 - 6 - @@ -16718,85 +16880,70 @@ 12 - 2 - 3 - 12 + 1 + 2 + 18 4 5 + 12 + + + 6 + 7 3 - - 5 - 6 - 9 - 7 - 10 - 9 + 8 + 12 - 10 + 8 15 - 6 + 12 15 - 16 - 6 + 18 + 12 - 17 - 19 - 9 - - - 20 + 18 22 - 6 + 9 22 - 28 - 9 + 30 + 12 - 29 - 37 - 9 + 31 + 73 + 12 - 54 - 95 - 9 - - - 106 + 95 165 - 9 + 12 - 227 - 336 - 9 + 230 + 409 + 12 - 398 - 711 - 9 + 645 + 1220 + 12 - 1055 - 1751 + 1766 + 4075 9 - - 1979 - 4068 - 6 - @@ -16811,7 +16958,7 @@ 1 2 - 42882 + 43301 @@ -16827,7 +16974,7 @@ 1 2 - 42882 + 43301 @@ -16837,26 +16984,26 @@ ruby_regex_def - 12828 + 12854 id - 12828 + 12854 ruby_rescue_body - 1794 + 1767 ruby_rescue - 1794 + 1767 body - 1794 + 1767 @@ -16870,7 +17017,7 @@ 1 2 - 1794 + 1767 @@ -16886,7 +17033,7 @@ 1 2 - 1794 + 1767 @@ -16896,26 +17043,26 @@ ruby_rescue_def - 2085 + 2061 id - 2085 + 2061 ruby_rescue_exceptions - 1641 + 1639 ruby_rescue - 1641 + 1639 exceptions - 1641 + 1639 @@ -16929,7 +17076,7 @@ 1 2 - 1641 + 1639 @@ -16945,7 +17092,7 @@ 1 2 - 1641 + 1639 @@ -16955,19 +17102,19 @@ ruby_rescue_modifier_def - 551 + 525 id - 551 + 525 body - 551 + 525 handler - 551 + 525 @@ -16981,7 +17128,7 @@ 1 2 - 551 + 525 @@ -16997,7 +17144,7 @@ 1 2 - 551 + 525 @@ -17013,7 +17160,7 @@ 1 2 - 551 + 525 @@ -17029,7 +17176,7 @@ 1 2 - 551 + 525 @@ -17045,7 +17192,7 @@ 1 2 - 551 + 525 @@ -17061,7 +17208,7 @@ 1 2 - 551 + 525 @@ -17071,15 +17218,15 @@ ruby_rescue_variable - 1021 + 1001 ruby_rescue - 1021 + 1001 variable - 1021 + 1001 @@ -17093,7 +17240,7 @@ 1 2 - 1021 + 1001 @@ -17109,7 +17256,7 @@ 1 2 - 1021 + 1001 @@ -17200,7 +17347,7 @@ 1 2 - 3 + 2 @@ -17216,7 +17363,7 @@ 1 2 - 3 + 2 @@ -17237,15 +17384,15 @@ ruby_return_child - 5359 + 5336 ruby_return - 5359 + 5336 child - 5359 + 5336 @@ -17259,7 +17406,7 @@ 1 2 - 5359 + 5336 @@ -17275,7 +17422,7 @@ 1 2 - 5359 + 5336 @@ -17285,22 +17432,22 @@ ruby_return_def - 8521 + 8495 id - 8521 + 8495 ruby_right_assignment_list_child - 2932 + 2757 ruby_right_assignment_list - 1376 + 1288 index @@ -17308,7 +17455,7 @@ child - 2932 + 2757 @@ -17322,7 +17469,7 @@ 2 3 - 1234 + 1147 3 @@ -17348,7 +17495,7 @@ 2 3 - 1234 + 1147 3 @@ -17387,8 +17534,8 @@ 3 - 437 - 438 + 409 + 410 6 @@ -17418,8 +17565,8 @@ 3 - 437 - 438 + 409 + 410 6 @@ -17436,7 +17583,7 @@ 1 2 - 2932 + 2757 @@ -17452,7 +17599,7 @@ 1 2 - 2932 + 2757 @@ -17462,26 +17609,26 @@ ruby_right_assignment_list_def - 1376 + 1288 id - 1376 + 1288 ruby_scope_resolution_def - 80201 + 80009 id - 80201 + 80009 name - 80201 + 80009 @@ -17495,7 +17642,7 @@ 1 2 - 80201 + 80009 @@ -17511,7 +17658,7 @@ 1 2 - 80201 + 80009 @@ -17521,15 +17668,15 @@ ruby_scope_resolution_scope - 78442 + 78256 ruby_scope_resolution - 78442 + 78256 scope - 78442 + 78256 @@ -17543,7 +17690,7 @@ 1 2 - 78442 + 78256 @@ -17559,7 +17706,7 @@ 1 2 - 78442 + 78256 @@ -17617,19 +17764,19 @@ ruby_singleton_class_child - 2422 + 2322 ruby_singleton_class - 626 + 620 index - 75 + 72 child - 2422 + 2322 @@ -17653,17 +17800,17 @@ 3 4 - 37 + 40 4 5 - 44 + 40 5 6 - 37 + 40 6 @@ -17672,18 +17819,13 @@ 8 - 12 - 47 + 13 + 53 - 12 + 13 24 - 47 - - - 24 - 25 - 3 + 34 @@ -17709,17 +17851,17 @@ 3 4 - 37 + 40 4 5 - 44 + 40 5 6 - 37 + 40 6 @@ -17728,18 +17870,13 @@ 8 - 12 - 47 + 13 + 53 - 12 + 13 24 - 47 - - - 24 - 25 - 3 + 34 @@ -17754,8 +17891,13 @@ 1 + 2 + 3 + + + 2 3 - 6 + 9 3 @@ -17763,18 +17905,13 @@ 9 - 4 - 5 - 9 - - - 7 - 9 + 6 + 8 6 - 10 - 13 + 9 + 12 6 @@ -17783,28 +17920,28 @@ 6 - 20 - 24 + 21 + 23 6 - 31 - 36 + 28 + 33 6 - 45 - 58 + 42 + 56 6 - 71 - 84 + 68 + 82 6 - 109 - 200 + 107 + 198 6 @@ -17820,8 +17957,13 @@ 1 + 2 + 3 + + + 2 3 - 6 + 9 3 @@ -17829,18 +17971,13 @@ 9 - 4 - 5 - 9 - - - 7 - 9 + 6 + 8 6 - 10 - 13 + 9 + 12 6 @@ -17849,28 +17986,28 @@ 6 - 20 - 24 + 21 + 23 6 - 31 - 36 + 28 + 33 6 - 45 - 58 + 42 + 56 6 - 71 - 84 + 68 + 82 6 - 109 - 200 + 107 + 198 6 @@ -17887,7 +18024,7 @@ 1 2 - 2422 + 2322 @@ -17903,7 +18040,7 @@ 1 2 - 2422 + 2322 @@ -17913,15 +18050,15 @@ ruby_singleton_class_def - 626 + 620 id - 626 + 620 value - 626 + 620 @@ -17935,7 +18072,7 @@ 1 2 - 626 + 620 @@ -17951,7 +18088,7 @@ 1 2 - 626 + 620 @@ -17961,19 +18098,19 @@ ruby_singleton_method_child - 16000 + 16018 ruby_singleton_method - 6563 + 6539 index - 84 + 89 child - 16000 + 16018 @@ -17987,32 +18124,32 @@ 1 2 - 3713 + 3714 2 3 - 985 + 965 3 4 - 588 + 612 4 5 - 403 + 374 5 8 - 518 + 505 8 - 29 - 354 + 31 + 368 @@ -18028,32 +18165,32 @@ 1 2 - 3713 + 3714 2 3 - 985 + 965 3 4 - 588 + 612 4 5 - 403 + 374 5 8 - 518 + 505 8 - 29 - 354 + 31 + 368 @@ -18069,72 +18206,77 @@ 1 2 - 3 + 2 2 3 - 6 + 11 3 4 - 6 + 5 + + + 4 + 5 + 2 5 6 - 12 + 8 - 7 - 9 - 6 + 9 + 10 + 5 - 10 - 15 - 6 + 12 + 17 + 5 - 22 - 27 - 6 + 23 + 28 + 5 - 30 - 38 - 6 + 32 + 41 + 5 - 49 - 63 - 6 + 51 + 66 + 5 - 87 - 118 - 6 + 93 + 125 + 5 - 148 - 202 - 6 + 155 + 210 + 5 - 288 - 422 - 6 + 294 + 421 + 5 - 615 - 941 - 6 + 626 + 952 + 5 - 2165 - 2166 - 3 + 2201 + 2202 + 2 @@ -18150,72 +18292,77 @@ 1 2 - 3 + 2 2 3 - 6 + 11 3 4 - 6 + 5 + + + 4 + 5 + 2 5 6 - 12 + 8 - 7 - 9 - 6 + 9 + 10 + 5 - 10 - 15 - 6 + 12 + 17 + 5 - 22 - 27 - 6 + 23 + 28 + 5 - 30 - 38 - 6 + 32 + 41 + 5 - 49 - 63 - 6 + 51 + 66 + 5 - 87 - 118 - 6 + 93 + 125 + 5 - 148 - 202 - 6 + 155 + 210 + 5 - 288 - 422 - 6 + 294 + 421 + 5 - 615 - 941 - 6 + 626 + 952 + 5 - 2165 - 2166 - 3 + 2201 + 2202 + 2 @@ -18231,7 +18378,7 @@ 1 2 - 16000 + 16018 @@ -18247,7 +18394,7 @@ 1 2 - 16000 + 16018 @@ -18257,19 +18404,19 @@ ruby_singleton_method_def - 6563 + 6539 id - 6563 + 6539 name - 6563 + 6539 object - 6563 + 6539 @@ -18283,7 +18430,7 @@ 1 2 - 6563 + 6539 @@ -18299,7 +18446,7 @@ 1 2 - 6563 + 6539 @@ -18315,7 +18462,7 @@ 1 2 - 6563 + 6539 @@ -18331,7 +18478,7 @@ 1 2 - 6563 + 6539 @@ -18347,7 +18494,7 @@ 1 2 - 6563 + 6539 @@ -18363,7 +18510,7 @@ 1 2 - 6563 + 6539 @@ -18373,15 +18520,15 @@ ruby_singleton_method_parameters - 4135 + 4082 ruby_singleton_method - 4135 + 4082 parameters - 4135 + 4082 @@ -18395,7 +18542,7 @@ 1 2 - 4135 + 4082 @@ -18411,7 +18558,7 @@ 1 2 - 4135 + 4082 @@ -18421,15 +18568,15 @@ ruby_splat_argument_def - 3179 + 3046 id - 3179 + 3046 child - 3179 + 3046 @@ -18443,7 +18590,7 @@ 1 2 - 3179 + 3046 @@ -18459,7 +18606,7 @@ 1 2 - 3179 + 3046 @@ -18469,26 +18616,26 @@ ruby_splat_parameter_def - 2936 + 2905 id - 2936 + 2905 ruby_splat_parameter_name - 2369 + 2354 ruby_splat_parameter - 2369 + 2354 name - 2369 + 2354 @@ -18502,7 +18649,7 @@ 1 2 - 2369 + 2354 @@ -18518,7 +18665,7 @@ 1 2 - 2369 + 2354 @@ -18528,11 +18675,11 @@ ruby_string_array_child - 11474 + 11487 ruby_string_array - 3716 + 3704 index @@ -18540,7 +18687,7 @@ child - 11474 + 11487 @@ -18554,32 +18701,32 @@ 1 2 - 1205 + 1200 2 3 - 1226 + 1218 3 4 - 579 + 576 4 5 - 290 + 294 5 10 - 283 + 282 10 461 - 133 + 134 @@ -18595,32 +18742,32 @@ 1 2 - 1205 + 1200 2 3 - 1226 + 1218 3 4 - 579 + 576 4 5 - 290 + 294 5 10 - 283 + 282 10 461 - 133 + 134 @@ -18649,8 +18796,8 @@ 35 - 706 - 3717 + 710 + 3705 4 @@ -18680,8 +18827,8 @@ 35 - 706 - 3717 + 710 + 3705 4 @@ -18698,7 +18845,7 @@ 1 2 - 11474 + 11487 @@ -18714,7 +18861,7 @@ 1 2 - 11474 + 11487 @@ -18724,22 +18871,22 @@ ruby_string_array_def - 3868 + 3840 id - 3868 + 3840 ruby_string_child - 535162 + 534498 ruby_string__ - 467438 + 466613 index @@ -18747,7 +18894,7 @@ child - 535162 + 534498 @@ -18761,12 +18908,12 @@ 1 2 - 440917 + 439982 2 282 - 26521 + 26631 @@ -18782,12 +18929,12 @@ 1 2 - 440917 + 439982 2 282 - 26521 + 26631 @@ -18827,7 +18974,7 @@ 102 - 467439 + 466614 22 @@ -18868,7 +19015,7 @@ 102 - 467439 + 466614 22 @@ -18885,7 +19032,7 @@ 1 2 - 535162 + 534498 @@ -18901,7 +19048,7 @@ 1 2 - 535162 + 534498 @@ -18911,22 +19058,22 @@ ruby_string_def - 474637 + 473533 id - 474637 + 473533 ruby_subshell_child - 645 + 620 ruby_subshell - 409 + 403 index @@ -18934,7 +19081,7 @@ child - 645 + 620 @@ -18948,22 +19095,22 @@ 1 2 - 308 + 296 2 3 - 53 + 59 3 - 6 - 28 + 4 + 18 - 6 + 4 12 - 18 + 28 @@ -18979,22 +19126,22 @@ 1 2 - 308 + 296 2 3 - 53 + 59 3 - 6 - 28 + 4 + 18 - 6 + 4 12 - 18 + 28 @@ -19015,16 +19162,11 @@ 2 3 - 3 + 6 - 6 - 7 - 3 - - - 7 - 8 + 3 + 4 3 @@ -19038,13 +19180,13 @@ 3 - 32 - 33 + 34 + 35 3 - 130 - 131 + 128 + 129 3 @@ -19066,16 +19208,11 @@ 2 3 - 3 + 6 - 6 - 7 - 3 - - - 7 - 8 + 3 + 4 3 @@ -19089,13 +19226,13 @@ 3 - 32 - 33 + 34 + 35 3 - 130 - 131 + 128 + 129 3 @@ -19112,7 +19249,7 @@ 1 2 - 645 + 620 @@ -19128,7 +19265,7 @@ 1 2 - 645 + 620 @@ -19138,26 +19275,26 @@ ruby_subshell_def - 409 + 403 id - 409 + 403 ruby_superclass_def - 13262 + 13318 id - 13262 + 13318 child - 13262 + 13318 @@ -19171,7 +19308,7 @@ 1 2 - 13262 + 13318 @@ -19187,7 +19324,7 @@ 1 2 - 13262 + 13318 @@ -19197,19 +19334,19 @@ ruby_symbol_array_child - 2137 + 2106 ruby_symbol_array - 457 + 463 index - 100 + 98 child - 2137 + 2106 @@ -19223,42 +19360,42 @@ 1 2 - 175 + 184 2 3 - 93 + 92 3 4 - 39 + 38 4 6 - 21 + 26 6 8 - 39 + 35 8 13 - 36 + 38 13 - 21 - 36 + 22 + 38 - 21 + 27 34 - 15 + 8 @@ -19274,42 +19411,42 @@ 1 2 - 175 + 184 2 3 - 93 + 92 3 4 - 39 + 38 4 6 - 21 + 26 6 8 - 39 + 35 8 13 - 36 + 38 13 - 21 - 36 + 22 + 38 - 21 + 27 34 - 15 + 8 @@ -19325,52 +19462,52 @@ 1 2 - 12 + 11 2 3 - 15 + 5 3 4 - 9 + 17 5 7 - 9 + 8 7 11 - 9 + 8 13 - 18 - 9 + 17 + 8 - 19 - 23 - 9 + 18 + 24 + 8 - 27 - 35 - 9 + 26 + 34 + 8 - 42 - 50 - 9 + 41 + 51 + 8 - 62 - 152 - 9 + 63 + 157 + 8 @@ -19386,52 +19523,52 @@ 1 2 - 12 + 11 2 3 - 15 + 5 3 4 - 9 + 17 5 7 - 9 + 8 7 11 - 9 + 8 13 - 18 - 9 + 17 + 8 - 19 - 23 - 9 + 18 + 24 + 8 - 27 - 35 - 9 + 26 + 34 + 8 - 42 - 50 - 9 + 41 + 51 + 8 - 62 - 152 - 9 + 63 + 157 + 8 @@ -19447,7 +19584,7 @@ 1 2 - 2137 + 2106 @@ -19463,7 +19600,7 @@ 1 2 - 2137 + 2106 @@ -19473,30 +19610,30 @@ ruby_symbol_array_def - 457 + 463 id - 457 + 463 ruby_then_child - 41524 + 41375 ruby_then - 24592 + 24329 index - 106 + 288 child - 41524 + 41375 @@ -19510,22 +19647,22 @@ 1 2 - 15349 + 15210 2 3 - 5541 + 5479 3 4 - 2031 + 2011 4 - 36 - 1670 + 98 + 1628 @@ -19541,22 +19678,22 @@ 1 2 - 15349 + 15210 2 3 - 5541 + 5479 3 4 - 2031 + 2011 4 - 36 - 1670 + 98 + 1628 @@ -19572,42 +19709,32 @@ 1 2 - 36 + 184 2 - 3 - 6 + 4 + 20 4 - 5 - 18 + 7 + 20 - 6 - 10 - 9 + 7 + 12 + 23 - 11 - 29 - 9 + 12 + 157 + 23 - 42 - 92 - 9 - - - 157 - 552 - 9 - - - 1221 - 8113 - 9 + 292 + 8189 + 14 @@ -19623,42 +19750,32 @@ 1 2 - 36 + 184 2 - 3 - 6 + 4 + 20 4 - 5 - 18 + 7 + 20 - 6 - 10 - 9 + 7 + 12 + 23 - 11 - 29 - 9 + 12 + 157 + 23 - 42 - 92 - 9 - - - 157 - 552 - 9 - - - 1221 - 8113 - 9 + 292 + 8189 + 14 @@ -19674,7 +19791,7 @@ 1 2 - 41524 + 41375 @@ -19690,7 +19807,7 @@ 1 2 - 41524 + 41375 @@ -19700,30 +19817,30 @@ ruby_then_def - 24592 + 24329 id - 24592 + 24329 ruby_tokeninfo - 5922021 + 5932219 id - 5922021 + 5932219 kind - 69 + 65 value - 270444 + 268924 @@ -19737,7 +19854,7 @@ 1 2 - 5922021 + 5932219 @@ -19753,7 +19870,7 @@ 1 2 - 5922021 + 5932219 @@ -19767,64 +19884,64 @@ 12 - 1 - 35 - 6 + 36 + 154 + 5 - 149 - 216 - 6 + 218 + 427 + 5 - 426 - 1594 - 6 + 1610 + 1611 + 2 - 1759 - 1760 - 6 + 1805 + 1806 + 5 - 3972 - 4099 - 6 + 3990 + 4222 + 5 - 4151 - 5588 - 6 + 4225 + 5692 + 5 - 7608 - 9506 - 6 + 7841 + 9805 + 5 - 13384 - 17043 - 6 + 13552 + 17172 + 5 - 24845 - 53463 - 6 + 25328 + 54391 + 5 - 54287 - 77797 - 6 + 55573 + 79435 + 5 - 93626 - 488897 - 6 + 95059 + 499129 + 5 - 1089226 - 1089227 - 3 + 1115017 + 1115018 + 2 @@ -19840,52 +19957,52 @@ 1 2 - 18 + 14 5 - 26 - 6 + 22 + 5 - 46 - 57 - 6 + 25 + 30 + 5 - 66 - 121 - 6 + 69 + 123 + 5 123 - 147 - 6 + 148 + 5 - 1472 - 1747 - 6 + 1480 + 1754 + 5 - 3017 - 3685 - 6 + 3052 + 3730 + 5 - 4567 - 7583 - 6 + 4632 + 7672 + 5 - 9961 - 18415 - 6 + 10019 + 18637 + 5 - 43711 - 43712 - 3 + 44586 + 44587 + 2 @@ -19901,32 +20018,32 @@ 1 2 - 160511 + 159668 2 3 - 39768 + 39566 3 4 - 19017 + 18844 4 7 - 22464 + 22228 7 27 - 20427 + 20374 27 - 178897 - 8255 + 183191 + 8242 @@ -19942,12 +20059,12 @@ 1 2 - 257002 + 255594 2 5 - 13442 + 13329 @@ -19957,15 +20074,15 @@ ruby_unary_def - 12512 + 13057 id - 12512 + 13057 operand - 12512 + 13057 operator @@ -19983,7 +20100,7 @@ 1 2 - 12512 + 13057 @@ -19999,7 +20116,7 @@ 1 2 - 12512 + 13057 @@ -20015,7 +20132,7 @@ 1 2 - 12512 + 13057 @@ -20031,7 +20148,7 @@ 1 2 - 12512 + 13057 @@ -20050,28 +20167,28 @@ 1 - 237 - 238 + 236 + 237 1 - 559 - 560 + 557 + 558 1 - 1311 - 1312 + 1312 + 1313 1 - 1747 - 1748 + 1742 + 1743 1 - 8570 - 8571 + 9122 + 9123 1 @@ -20091,28 +20208,28 @@ 1 - 237 - 238 + 236 + 237 1 - 559 - 560 + 557 + 558 1 - 1311 - 1312 + 1312 + 1313 1 - 1747 - 1748 + 1742 + 1743 1 - 8570 - 8571 + 9122 + 9123 1 @@ -20318,15 +20435,15 @@ ruby_unless_consequence - 2567 + 2575 ruby_unless - 2567 + 2575 consequence - 2567 + 2575 @@ -20340,7 +20457,7 @@ 1 2 - 2567 + 2575 @@ -20356,7 +20473,7 @@ 1 2 - 2567 + 2575 @@ -20366,15 +20483,15 @@ ruby_unless_def - 2568 + 2578 id - 2568 + 2578 condition - 2568 + 2578 @@ -20388,7 +20505,7 @@ 1 2 - 2568 + 2578 @@ -20404,7 +20521,7 @@ 1 2 - 2568 + 2578 @@ -20436,7 +20553,7 @@ 1 2 - 3 + 2 @@ -20456,19 +20573,19 @@ ruby_unless_modifier_def - 4341 + 4207 id - 4341 + 4207 body - 4341 + 4207 condition - 4341 + 4207 @@ -20482,7 +20599,7 @@ 1 2 - 4341 + 4207 @@ -20498,7 +20615,7 @@ 1 2 - 4341 + 4207 @@ -20514,7 +20631,7 @@ 1 2 - 4341 + 4207 @@ -20530,7 +20647,7 @@ 1 2 - 4341 + 4207 @@ -20546,7 +20663,7 @@ 1 2 - 4341 + 4207 @@ -20562,7 +20679,7 @@ 1 2 - 4341 + 4207 @@ -20572,19 +20689,19 @@ ruby_until_def - 114 + 113 id - 114 + 113 body - 114 + 113 condition - 114 + 113 @@ -20598,7 +20715,7 @@ 1 2 - 114 + 113 @@ -20614,7 +20731,7 @@ 1 2 - 114 + 113 @@ -20630,7 +20747,7 @@ 1 2 - 114 + 113 @@ -20646,7 +20763,7 @@ 1 2 - 114 + 113 @@ -20662,7 +20779,7 @@ 1 2 - 114 + 113 @@ -20678,7 +20795,7 @@ 1 2 - 114 + 113 @@ -20688,19 +20805,19 @@ ruby_until_modifier_def - 218 + 206 id - 218 + 206 body - 218 + 206 condition - 218 + 206 @@ -20714,7 +20831,7 @@ 1 2 - 218 + 206 @@ -20730,7 +20847,7 @@ 1 2 - 218 + 206 @@ -20746,7 +20863,7 @@ 1 2 - 218 + 206 @@ -20762,7 +20879,7 @@ 1 2 - 218 + 206 @@ -20778,7 +20895,7 @@ 1 2 - 218 + 206 @@ -20794,7 +20911,7 @@ 1 2 - 218 + 206 @@ -20826,7 +20943,7 @@ 1 2 - 3 + 2 @@ -20846,15 +20963,15 @@ ruby_when_body - 3194 + 3208 ruby_when - 3194 + 3208 body - 3194 + 3208 @@ -20868,7 +20985,7 @@ 1 2 - 3194 + 3208 @@ -20884,7 +21001,7 @@ 1 2 - 3194 + 3208 @@ -20894,22 +21011,22 @@ ruby_when_def - 3229 + 3239 id - 3229 + 3239 ruby_when_pattern - 3878 + 3895 ruby_when - 3229 + 3239 index @@ -20917,7 +21034,7 @@ pattern - 3878 + 3895 @@ -20931,7 +21048,7 @@ 1 2 - 2822 + 2830 2 @@ -20941,7 +21058,7 @@ 3 15 - 100 + 103 @@ -20957,7 +21074,7 @@ 1 2 - 2822 + 2830 2 @@ -20967,7 +21084,7 @@ 3 15 - 100 + 103 @@ -21006,18 +21123,18 @@ 3 - 32 - 33 + 33 + 34 3 - 129 - 130 + 130 + 131 3 - 1025 - 1026 + 1028 + 1029 3 @@ -21057,18 +21174,18 @@ 3 - 32 - 33 + 33 + 34 3 - 129 - 130 + 130 + 131 3 - 1025 - 1026 + 1028 + 1029 3 @@ -21085,7 +21202,7 @@ 1 2 - 3878 + 3895 @@ -21101,7 +21218,7 @@ 1 2 - 3878 + 3895 @@ -21111,19 +21228,19 @@ ruby_while_def - 1344 + 1335 id - 1344 + 1335 body - 1344 + 1335 condition - 1344 + 1335 @@ -21137,7 +21254,7 @@ 1 2 - 1344 + 1335 @@ -21153,7 +21270,7 @@ 1 2 - 1344 + 1335 @@ -21169,7 +21286,7 @@ 1 2 - 1344 + 1335 @@ -21185,7 +21302,7 @@ 1 2 - 1344 + 1335 @@ -21201,7 +21318,7 @@ 1 2 - 1344 + 1335 @@ -21217,7 +21334,7 @@ 1 2 - 1344 + 1335 @@ -21227,19 +21344,19 @@ ruby_while_modifier_def - 184 + 179 id - 184 + 179 body - 184 + 179 condition - 184 + 179 @@ -21253,7 +21370,7 @@ 1 2 - 184 + 179 @@ -21269,7 +21386,7 @@ 1 2 - 184 + 179 @@ -21285,7 +21402,7 @@ 1 2 - 184 + 179 @@ -21301,7 +21418,7 @@ 1 2 - 184 + 179 @@ -21317,7 +21434,7 @@ 1 2 - 184 + 179 @@ -21333,7 +21450,7 @@ 1 2 - 184 + 179 @@ -21343,15 +21460,15 @@ ruby_yield_child - 1115 + 1112 ruby_yield - 1115 + 1112 child - 1115 + 1112 @@ -21365,7 +21482,7 @@ 1 2 - 1115 + 1112 @@ -21381,7 +21498,7 @@ 1 2 - 1115 + 1112 @@ -21391,11 +21508,11 @@ ruby_yield_def - 2406 + 2385 id - 2406 + 2385 From 20a3e3a8aead302867988f7d49bc7d21a696e6ee Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Tue, 26 Apr 2022 15:26:13 +0200 Subject: [PATCH 103/171] Update library --- ruby/ql/lib/codeql/ruby/ast/Method.qll | 18 +++++++++ ruby/ql/lib/codeql/ruby/ast/internal/AST.qll | 36 ++++++++--------- ruby/ql/lib/codeql/ruby/ast/internal/Call.qll | 40 ++----------------- .../lib/codeql/ruby/ast/internal/Literal.qll | 11 +++-- .../lib/codeql/ruby/ast/internal/Method.qll | 4 ++ .../codeql/ruby/ast/internal/Synthesis.qll | 7 +--- .../lib/codeql/ruby/ast/internal/Variable.qll | 5 ++- .../internal/ControlFlowGraphImpl.qll | 14 ++++++- 8 files changed, 68 insertions(+), 67 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/ast/Method.qll b/ruby/ql/lib/codeql/ruby/ast/Method.qll index 824a0b6954a..8e4ea870e03 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Method.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Method.qll @@ -252,10 +252,24 @@ class Lambda extends Callable, BodyStmt, TLambda { /** A block. */ class Block extends Callable, StmtSequence, Scope, TBlock { + /** + * Get a local variable declared by this block. + * For example `local` in `{ | param; local| puts param }`. + */ + LocalVariableWriteAccess getALocalVariable() { result = this.getLocalVariable(_) } + + /** + * Gets the `n`th local variable declared by this block. + * For example `local` in `{ | param; local| puts param }`. + */ + LocalVariableWriteAccess getLocalVariable(int n) { none() } + override AstNode getAChild(string pred) { result = Callable.super.getAChild(pred) or result = StmtSequence.super.getAChild(pred) + or + pred = "getLocalVariable" and result = this.getLocalVariable(_) } } @@ -265,6 +279,10 @@ class DoBlock extends Block, BodyStmt, TDoBlock { DoBlock() { this = TDoBlock(g) } + final override LocalVariableWriteAccess getLocalVariable(int n) { + toGenerated(result) = g.getParameters().getLocals(n) + } + final override Parameter getParameter(int n) { toGenerated(result) = g.getParameters().getChild(n) } diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll b/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll index 5a59b56bcf5..11499454a75 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll @@ -138,7 +138,9 @@ private module Cached { TFalseLiteral(Ruby::False g) or TFile(Ruby::File g) or TFindPattern(Ruby::FindPattern g) or - TFloatLiteral(Ruby::Float g) { not any(Ruby::Rational r).getChild() = g } or + TFloatLiteral(Ruby::Float g) { + not any(Ruby::Complex r).getChild() = g and not any(Ruby::Rational r).getChild() = g + } or TForExpr(Ruby::For g) or TForwardParameter(Ruby::ForwardParameter g) or TForwardArgument(Ruby::ForwardArgument g) or @@ -169,7 +171,9 @@ private module Cached { TInstanceVariableAccessSynth(AST::AstNode parent, int i, AST::InstanceVariable v) { mkSynthChild(InstanceVariableAccessKind(v), parent, i) } or - TIntegerLiteralReal(Ruby::Integer g) { not any(Ruby::Rational r).getChild() = g } or + TIntegerLiteralReal(Ruby::Integer g) { + not any(Ruby::Complex r).getChild() = g and not any(Ruby::Rational r).getChild() = g + } or TIntegerLiteralSynth(AST::AstNode parent, int i, int value) { mkSynthChild(IntegerLiteralKind(value), parent, i) } or @@ -223,7 +227,7 @@ private module Cached { TRangeLiteralSynth(AST::AstNode parent, int i, boolean inclusive) { mkSynthChild(RangeLiteralKind(inclusive), parent, i) } or - TRationalLiteral(Ruby::Rational g) or + TRationalLiteral(Ruby::Rational g) { not any(Ruby::Complex r).getChild() = g } or TRedoStmt(Ruby::Redo g) or TRegExpLiteral(Ruby::Regex g) or TRegExpMatchExpr(Ruby::Binary g) { g instanceof @ruby_binary_equaltilde } or @@ -248,9 +252,6 @@ private module Cached { casePattern(g) ) } or - TScopeResolutionMethodCall(Ruby::ScopeResolution g, Ruby::Identifier i) { - isScopeResolutionMethodCall(g, i) - } or TSelfReal(Ruby::Self g) or TSelfSynth(AST::AstNode parent, int i, AST::SelfVariable v) { mkSynthChild(SelfKind(v), parent, i) @@ -356,15 +357,15 @@ private module Cached { TRShiftExprReal or TRangeLiteralReal or TRationalLiteral or TRedoStmt or TRegExpLiteral or TRegExpMatchExpr or TRegularArrayLiteral or TRegularMethodCall or TRegularStringLiteral or TRegularSuperCall or TRescueClause or TRescueModifierExpr or TRetryStmt or TReturnStmt or - TScopeResolutionConstantAccess or TScopeResolutionMethodCall or TSelfReal or - TSimpleParameterReal or TSimpleSymbolLiteral or TSingletonClass or TSingletonMethod or - TSpaceshipExpr or TSplatExprReal or TSplatParameter or TStringArrayLiteral or - TStringConcatenation or TStringEscapeSequenceComponent or TStringInterpolationComponent or - TStringTextComponent or TSubExprReal or TSubshellLiteral or TSymbolArrayLiteral or - TTernaryIfExpr or TThen or TTokenConstantAccess or TTokenMethodName or TTokenSuperCall or - TToplevel or TTrueLiteral or TUnaryMinusExpr or TUnaryPlusExpr or TUndefStmt or - TUnlessExpr or TUnlessModifierExpr or TUntilExpr or TUntilModifierExpr or - TReferencePattern or TWhenClause or TWhileExpr or TWhileModifierExpr or TYieldCall; + TScopeResolutionConstantAccess or TSelfReal or TSimpleParameterReal or + TSimpleSymbolLiteral or TSingletonClass or TSingletonMethod or TSpaceshipExpr or + TSplatExprReal or TSplatParameter or TStringArrayLiteral or TStringConcatenation or + TStringEscapeSequenceComponent or TStringInterpolationComponent or TStringTextComponent or + TSubExprReal or TSubshellLiteral or TSymbolArrayLiteral or TTernaryIfExpr or TThen or + TTokenConstantAccess or TTokenMethodName or TTokenSuperCall or TToplevel or TTrueLiteral or + TUnaryMinusExpr or TUnaryPlusExpr or TUndefStmt or TUnlessExpr or TUnlessModifierExpr or + TUntilExpr or TUntilModifierExpr or TReferencePattern or TWhenClause or TWhileExpr or + TWhileModifierExpr or TYieldCall; class TAstNodeSynth = TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or @@ -498,7 +499,6 @@ private module Cached { n = TReturnStmt(result) or n = TRShiftExprReal(result) or n = TScopeResolutionConstantAccess(result, _) or - n = TScopeResolutionMethodCall(result, _) or n = TSelfReal(result) or n = TSimpleParameterReal(result) or n = TSimpleSymbolLiteral(result) or @@ -659,8 +659,8 @@ class TCall = TMethodCall or TYieldCall; class TCase = TCaseExpr or TCaseMatch; class TMethodCall = - TMethodCallSynth or TIdentifierMethodCall or TScopeResolutionMethodCall or TRegularMethodCall or - TElementReference or TSuperCall or TUnaryOperation or TBinaryOperation; + TMethodCallSynth or TIdentifierMethodCall or TRegularMethodCall or TElementReference or + TSuperCall or TUnaryOperation or TBinaryOperation; class TSuperCall = TTokenSuperCall or TRegularSuperCall; diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll index 58e9f912091..25f2e2a305a 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll @@ -7,11 +7,6 @@ predicate isIdentifierMethodCall(Ruby::Identifier g) { vcall(g) and not access(g predicate isRegularMethodCall(Ruby::Call g) { not g.getMethod() instanceof Ruby::Super } -predicate isScopeResolutionMethodCall(Ruby::ScopeResolution g, Ruby::Identifier i) { - i = g.getName() and - not exists(Ruby::Call c | c.getMethod() = g) -} - abstract class CallImpl extends Expr, TCall { abstract AstNode getArgumentImpl(int n); @@ -69,23 +64,6 @@ class IdentifierMethodCall extends MethodCallImpl, TIdentifierMethodCall { final override Block getBlockImpl() { none() } } -class ScopeResolutionMethodCall extends MethodCallImpl, TScopeResolutionMethodCall { - private Ruby::ScopeResolution g; - private Ruby::Identifier i; - - ScopeResolutionMethodCall() { this = TScopeResolutionMethodCall(g, i) } - - final override string getMethodNameImpl() { result = i.getValue() } - - final override Expr getReceiverImpl() { toGenerated(result) = g.getScope() } - - final override Expr getArgumentImpl(int n) { none() } - - final override int getNumberOfArgumentsImpl() { result = 0 } - - final override Block getBlockImpl() { none() } -} - class RegularMethodCall extends MethodCallImpl, TRegularMethodCall { private Ruby::Call g; @@ -94,33 +72,21 @@ class RegularMethodCall extends MethodCallImpl, TRegularMethodCall { final override Expr getReceiverImpl() { toGenerated(result) = g.getReceiver() or - not exists(g.getReceiver()) and - toGenerated(result) = g.getMethod().(Ruby::ScopeResolution).getScope() - or result = TSelfSynth(this, 0, _) } final override string getMethodNameImpl() { isRegularMethodCall(g) and ( - result = "call" and g.getMethod() instanceof Ruby::ArgumentList + result = "call" and not exists(g.getMethod()) or result = g.getMethod().(Ruby::Token).getValue() - or - result = g.getMethod().(Ruby::ScopeResolution).getName().(Ruby::Token).getValue() ) } - final override Expr getArgumentImpl(int n) { - toGenerated(result) = g.getArguments().getChild(n) - or - toGenerated(result) = g.getMethod().(Ruby::ArgumentList).getChild(n) - } + final override Expr getArgumentImpl(int n) { toGenerated(result) = g.getArguments().getChild(n) } - final override int getNumberOfArgumentsImpl() { - result = - count(g.getArguments().getChild(_)) + count(g.getMethod().(Ruby::ArgumentList).getChild(_)) - } + final override int getNumberOfArgumentsImpl() { result = count(g.getArguments().getChild(_)) } final override Block getBlockImpl() { toGenerated(result) = g.getBlock() } } diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Literal.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Literal.qll index 78dadd5315e..cbdd65a19ca 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Literal.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Literal.qll @@ -88,9 +88,11 @@ class RationalLiteralImpl extends Expr, TRationalLiteral { } float getComplexValue(Ruby::Complex c) { + exists(int n, int d | isRationalValue(c.getChild(), n, d) and result = n.(float) / d.(float)) + or exists(string s | - s = c.getValue() and - result = s.prefix(s.length() - 1).toFloat() + s = c.getChild().(Ruby::Token).getValue() and + result = s.prefix(s.length()).toFloat() ) } @@ -103,7 +105,10 @@ class ComplexLiteralImpl extends Expr, TComplexLiteral { real = 0 and imaginary = getComplexValue(g) } - final override string toString() { result = g.getValue() } + final override string toString() { + result = g.getChild().(Ruby::Token).getValue() + "i" or + result = g.getChild().(Ruby::Rational).getChild().(Ruby::Token).getValue() + "ri" + } } class NilLiteralImpl extends Expr, TNilLiteral { diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Method.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Method.qll index 09a16350096..0b923056441 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Method.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Method.qll @@ -7,6 +7,10 @@ class BraceBlockReal extends BraceBlock, TBraceBlockReal { BraceBlockReal() { this = TBraceBlockReal(g) } + final override LocalVariableWriteAccess getLocalVariable(int n) { + toGenerated(result) = g.getParameters().getLocals(n) + } + final override Parameter getParameter(int n) { toGenerated(result) = g.getParameters().getChild(n) } diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll index f3e3c479fb0..7b83965b03e 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll @@ -197,11 +197,8 @@ private module ImplicitSelfSynthesis { private predicate regularMethodCallSelfSynthesis(TRegularMethodCall mc, int i, Child child) { exists(Ruby::AstNode g | mc = TRegularMethodCall(g) and - // If there's no explicit receiver (or scope resolution that acts like a - // receiver), then the receiver is implicitly `self`. N.B. `::Foo()` is - // not valid Ruby. - not exists(g.(Ruby::Call).getReceiver()) and - not exists(g.(Ruby::Call).getMethod().(Ruby::ScopeResolution).getScope()) + // If there's no explicit receiver, then the receiver is implicitly `self`. + not exists(g.(Ruby::Call).getReceiver()) ) and child = SynthChild(SelfKind(TSelfVariable(scopeOf(toGenerated(mc)).getEnclosingSelfScope()))) and i = 0 diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll index a5e977bb1cb..64fcdbd669a 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll @@ -50,8 +50,9 @@ predicate implicitAssignmentNode(Ruby::AstNode n) { /** Holds if `n` is inside a parameter. */ predicate implicitParameterAssignmentNode(Ruby::AstNode n, Callable::Range c) { - n = c.getParameter(_) - or + n = c.getParameter(_) or + n = c.(Ruby::Block).getParameters().getLocals(_) or + n = c.(Ruby::DoBlock).getParameters().getLocals(_) or implicitParameterAssignmentNode(n.getParent().(Ruby::DestructuredParameter), c) } diff --git a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll index 641c78e3dee..435097900f8 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll @@ -347,7 +347,12 @@ module Trees { final override AstNode getBodyChild(int i, boolean rescuable) { result = this.getParameter(i) and rescuable = false or - result = StmtSequenceTree.super.getBodyChild(i - this.getNumberOfParameters(), rescuable) + result = this.getLocalVariable(i - this.getNumberOfParameters()) and rescuable = false + or + result = + StmtSequenceTree.super + .getBodyChild(i - this.getNumberOfParameters() - count(this.getALocalVariable()), + rescuable) } override predicate first(AstNode first) { first = this } @@ -959,7 +964,12 @@ module Trees { final override AstNode getBodyChild(int i, boolean rescuable) { result = this.getParameter(i) and rescuable = false or - result = BodyStmtTree.super.getBodyChild(i - this.getNumberOfParameters(), rescuable) + result = this.getLocalVariable(i - this.getNumberOfParameters()) and rescuable = false + or + result = + BodyStmtTree.super + .getBodyChild(i - this.getNumberOfParameters() - count(this.getALocalVariable()), + rescuable) } override predicate propagatesAbnormal(AstNode child) { none() } From d055f9a1861e016206c45de70021efffc7a00511 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Tue, 26 Apr 2022 18:51:55 +0200 Subject: [PATCH 104/171] Update tests --- ruby/ql/test/library-tests/ast/Ast.expected | 26 +- .../library-tests/ast/TreeSitter.expected | 388 +++++++++--------- .../test/library-tests/ast/ValueText.expected | 12 +- .../library-tests/ast/calls/calls.expected | 2 +- .../ast/literals/literals.expected | 15 +- .../library-tests/ast/literals/literals.rb | 6 +- .../library-tests/ast/params/params.expected | 3 + .../test/library-tests/ast/params/params.rb | 2 + .../controlflow/graph/Cfg.expected | 76 +++- .../controlflow/graph/Nodes.expected | 5 + .../library-tests/controlflow/graph/cfg.rb | 4 + .../variables/parameter.expected | 2 - 12 files changed, 330 insertions(+), 211 deletions(-) diff --git a/ruby/ql/test/library-tests/ast/Ast.expected b/ruby/ql/test/library-tests/ast/Ast.expected index adb3f41dec6..a8e67da4ec6 100644 --- a/ruby/ql/test/library-tests/ast/Ast.expected +++ b/ruby/ql/test/library-tests/ast/Ast.expected @@ -1716,11 +1716,11 @@ escape_sequences/escapes.rb: literals/literals.rb: # 1| [Toplevel] literals.rb # 2| getStmt: [NilLiteral] nil -# 3| getStmt: [NilLiteral] NIL +# 3| getStmt: [ConstantReadAccess] NIL # 4| getStmt: [BooleanLiteral] false -# 5| getStmt: [BooleanLiteral] FALSE +# 5| getStmt: [ConstantReadAccess] FALSE # 6| getStmt: [BooleanLiteral] true -# 7| getStmt: [BooleanLiteral] TRUE +# 7| getStmt: [ConstantReadAccess] TRUE # 10| getStmt: [IntegerLiteral] 1234 # 11| getStmt: [IntegerLiteral] 5_678 # 12| getStmt: [IntegerLiteral] 0 @@ -1752,6 +1752,8 @@ literals/literals.rb: # 48| getStmt: [RationalLiteral] 23r # 49| getStmt: [RationalLiteral] 9.85r # 52| getStmt: [ComplexLiteral] 2i +# 53| getStmt: [ComplexLiteral] 3.14i +# 56| getStmt: [ComplexLiteral] 1.2ri # 59| getStmt: [StringLiteral] "" # 60| getStmt: [StringLiteral] "" # 61| getStmt: [StringLiteral] "hello" @@ -2054,10 +2056,10 @@ literals/literals.rb: # 139| getStmt: [RangeLiteral] _ .. _ # 139| getEnd: [IntegerLiteral] 1 # 140| getStmt: [ParenthesizedExpr] ( ... ) -# 140| getStmt: [SubExpr] ... - ... -# 140| getAnOperand/getLeftOperand/getReceiver: [RangeLiteral] _ .. _ -# 140| getBegin: [IntegerLiteral] 0 -# 140| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1 +# 140| getStmt: [RangeLiteral] _ .. _ +# 140| getBegin: [IntegerLiteral] 0 +# 140| getEnd: [UnaryMinusExpr] - ... +# 140| getAnOperand/getOperand/getReceiver: [IntegerLiteral] 1 # 143| getStmt: [SubshellLiteral] `ls -l` # 143| getComponent: [StringTextComponent] ls -l # 144| getStmt: [SubshellLiteral] `ls -l` @@ -2990,6 +2992,16 @@ params/params.rb: # 83| getReceiver: [LocalVariableAccess] array # 83| getArgument: [BlockArgument] &... # 83| getValue: [LocalVariableAccess] __synth__0 +# 86| getStmt: [MethodCall] call to run_block +# 86| getReceiver: [SelfVariableAccess] self +# 86| getBlock: [BraceBlock] { ... } +# 86| getParameter: [SimpleParameter] x +# 86| getDefiningAccess: [LocalVariableAccess] x +# 86| getLocalVariable: [LocalVariableAccess] y +# 86| getLocalVariable: [LocalVariableAccess] z +# 86| getStmt: [MethodCall] call to puts +# 86| getReceiver: [SelfVariableAccess] self +# 86| getArgument: [LocalVariableAccess] x erb/template.html.erb: # 19| [Toplevel] template.html.erb # 19| getStmt: [StringLiteral] "hello world" diff --git a/ruby/ql/test/library-tests/ast/TreeSitter.expected b/ruby/ql/test/library-tests/ast/TreeSitter.expected index ecf00e54895..64cdabc5a46 100644 --- a/ruby/ql/test/library-tests/ast/TreeSitter.expected +++ b/ruby/ql/test/library-tests/ast/TreeSitter.expected @@ -6,17 +6,14 @@ calls/calls.rb: # 2| 0: [ReservedWord] ( # 2| 1: [ReservedWord] ) # 5| 1: [Call] Call -# 5| 0: [ScopeResolution] ScopeResolution -# 5| 0: [Constant] Foo -# 5| 1: [ReservedWord] :: -# 5| 2: [Identifier] bar -# 5| 1: [ArgumentList] ArgumentList +# 5| 0: [Constant] Foo +# 5| 1: [ReservedWord] :: +# 5| 2: [Identifier] bar +# 5| 3: [ArgumentList] ArgumentList # 5| 0: [ReservedWord] ( # 5| 1: [ReservedWord] ) # 8| 2: [Call] Call -# 8| 0: [ScopeResolution] ScopeResolution -# 8| 0: [ReservedWord] :: -# 8| 1: [Identifier] bar +# 8| 0: [Identifier] bar # 8| 1: [ArgumentList] ArgumentList # 8| 0: [ReservedWord] ( # 8| 1: [ReservedWord] ) @@ -97,7 +94,7 @@ calls/calls.rb: # 36| 2: [Integer] 200 # 37| 3: [ReservedWord] end # 46| 10: [Identifier] foo -# 47| 11: [ScopeResolution] ScopeResolution +# 47| 11: [Call] Call # 47| 0: [Constant] X # 47| 1: [ReservedWord] :: # 47| 2: [Identifier] foo @@ -107,7 +104,7 @@ calls/calls.rb: # 50| 2: [ReservedWord] ) # 51| 13: [ParenthesizedStatements] ParenthesizedStatements # 51| 0: [ReservedWord] ( -# 51| 1: [ScopeResolution] ScopeResolution +# 51| 1: [Call] Call # 51| 0: [Constant] X # 51| 1: [ReservedWord] :: # 51| 2: [Identifier] foo @@ -122,7 +119,7 @@ calls/calls.rb: # 55| 0: [Identifier] some_func # 55| 1: [ArgumentList] ArgumentList # 55| 0: [ReservedWord] ( -# 55| 1: [ScopeResolution] ScopeResolution +# 55| 1: [Call] Call # 55| 0: [Constant] X # 55| 1: [ReservedWord] :: # 55| 2: [Identifier] foo @@ -133,7 +130,7 @@ calls/calls.rb: # 58| 2: [ReservedWord] ] # 59| 17: [Array] Array # 59| 0: [ReservedWord] [ -# 59| 1: [ScopeResolution] ScopeResolution +# 59| 1: [Call] Call # 59| 0: [Constant] X # 59| 1: [ReservedWord] :: # 59| 2: [Identifier] foo @@ -145,7 +142,7 @@ calls/calls.rb: # 63| 19: [Assignment] Assignment # 63| 0: [Identifier] var1 # 63| 1: [ReservedWord] = -# 63| 2: [ScopeResolution] ScopeResolution +# 63| 2: [Call] Call # 63| 0: [Constant] X # 63| 1: [ReservedWord] :: # 63| 2: [Identifier] foo @@ -156,7 +153,7 @@ calls/calls.rb: # 67| 21: [OperatorAssignment] OperatorAssignment # 67| 0: [Identifier] var1 # 67| 1: [ReservedWord] += -# 67| 2: [ScopeResolution] ScopeResolution +# 67| 2: [Call] Call # 67| 0: [Constant] X # 67| 1: [ReservedWord] :: # 67| 2: [Identifier] bar @@ -166,14 +163,14 @@ calls/calls.rb: # 70| 2: [RightAssignmentList] RightAssignmentList # 70| 0: [Identifier] foo # 70| 1: [ReservedWord] , -# 70| 2: [ScopeResolution] ScopeResolution +# 70| 2: [Call] Call # 70| 0: [Constant] X # 70| 1: [ReservedWord] :: # 70| 2: [Identifier] bar # 73| 23: [Begin] Begin # 73| 0: [ReservedWord] begin # 74| 1: [Identifier] foo -# 75| 2: [ScopeResolution] ScopeResolution +# 75| 2: [Call] Call # 75| 0: [Constant] X # 75| 1: [ReservedWord] :: # 75| 2: [Identifier] foo @@ -183,7 +180,7 @@ calls/calls.rb: # 79| 1: [ReservedWord] { # 79| 2: [Identifier] foo # 79| 3: [ReservedWord] ; -# 79| 4: [ScopeResolution] ScopeResolution +# 79| 4: [Call] Call # 79| 0: [Constant] X # 79| 1: [ReservedWord] :: # 79| 2: [Identifier] bar @@ -193,7 +190,7 @@ calls/calls.rb: # 82| 1: [ReservedWord] { # 82| 2: [Identifier] foo # 82| 3: [ReservedWord] ; -# 82| 4: [ScopeResolution] ScopeResolution +# 82| 4: [Call] Call # 82| 0: [Constant] X # 82| 1: [ReservedWord] :: # 82| 2: [Identifier] bar @@ -201,7 +198,7 @@ calls/calls.rb: # 85| 26: [Binary] Binary # 85| 0: [Identifier] foo # 85| 1: [ReservedWord] + -# 85| 2: [ScopeResolution] ScopeResolution +# 85| 2: [Call] Call # 85| 0: [Constant] X # 85| 1: [ReservedWord] :: # 85| 2: [Identifier] bar @@ -210,7 +207,7 @@ calls/calls.rb: # 88| 1: [Identifier] foo # 89| 28: [Unary] Unary # 89| 0: [ReservedWord] ~ -# 89| 1: [ScopeResolution] ScopeResolution +# 89| 1: [Call] Call # 89| 0: [Constant] X # 89| 1: [ReservedWord] :: # 89| 2: [Identifier] bar @@ -223,7 +220,7 @@ calls/calls.rb: # 92| 0: [ReservedWord] { # 92| 1: [Identifier] bar # 92| 2: [ReservedWord] ; -# 92| 3: [ScopeResolution] ScopeResolution +# 92| 3: [Call] Call # 92| 0: [Constant] X # 92| 1: [ReservedWord] :: # 92| 2: [Identifier] baz @@ -236,7 +233,7 @@ calls/calls.rb: # 95| 2: [DoBlock] DoBlock # 95| 0: [ReservedWord] do # 96| 1: [Identifier] bar -# 97| 2: [ScopeResolution] ScopeResolution +# 97| 2: [Call] Call # 97| 0: [Constant] X # 97| 1: [ReservedWord] :: # 97| 2: [Identifier] baz @@ -267,19 +264,19 @@ calls/calls.rb: # 109| 3: [ReservedWord] end # 110| 34: [Case] Case # 110| 0: [ReservedWord] case -# 110| 1: [ScopeResolution] ScopeResolution +# 110| 1: [Call] Call # 110| 0: [Constant] X # 110| 1: [ReservedWord] :: # 110| 2: [Identifier] foo # 111| 2: [When] When # 111| 0: [ReservedWord] when # 111| 1: [Pattern] Pattern -# 111| 0: [ScopeResolution] ScopeResolution +# 111| 0: [Call] Call # 111| 0: [Constant] X # 111| 1: [ReservedWord] :: # 111| 2: [Identifier] bar # 111| 2: [Then] Then -# 112| 0: [ScopeResolution] ScopeResolution +# 112| 0: [Call] Call # 112| 0: [Constant] X # 112| 1: [ReservedWord] :: # 112| 2: [Identifier] baz @@ -288,7 +285,7 @@ calls/calls.rb: # 116| 0: [ReservedWord] class # 116| 1: [Constant] MyClass # 117| 2: [Identifier] foo -# 118| 3: [ScopeResolution] ScopeResolution +# 118| 3: [Call] Call # 118| 0: [Constant] X # 118| 1: [ReservedWord] :: # 118| 2: [Identifier] bar @@ -305,7 +302,7 @@ calls/calls.rb: # 124| 1: [Constant] MyClass2 # 124| 2: [Superclass] Superclass # 124| 0: [ReservedWord] < -# 124| 1: [ScopeResolution] ScopeResolution +# 124| 1: [Call] Call # 124| 0: [Constant] X # 124| 1: [ReservedWord] :: # 124| 2: [Identifier] foo @@ -319,11 +316,11 @@ calls/calls.rb: # 131| 39: [SingletonClass] SingletonClass # 131| 0: [ReservedWord] class # 131| 1: [ReservedWord] << -# 131| 2: [ScopeResolution] ScopeResolution +# 131| 2: [Call] Call # 131| 0: [Constant] X # 131| 1: [ReservedWord] :: # 131| 2: [Identifier] foo -# 132| 3: [ScopeResolution] ScopeResolution +# 132| 3: [Call] Call # 132| 0: [Constant] X # 132| 1: [ReservedWord] :: # 132| 2: [Identifier] bar @@ -332,7 +329,7 @@ calls/calls.rb: # 136| 0: [ReservedWord] def # 136| 1: [Identifier] some_method # 137| 2: [Identifier] foo -# 138| 3: [ScopeResolution] ScopeResolution +# 138| 3: [Call] Call # 138| 0: [Constant] X # 138| 1: [ReservedWord] :: # 138| 2: [Identifier] bar @@ -343,7 +340,7 @@ calls/calls.rb: # 142| 2: [ReservedWord] . # 142| 3: [Identifier] some_method # 143| 4: [Identifier] bar -# 144| 5: [ScopeResolution] ScopeResolution +# 144| 5: [Call] Call # 144| 0: [Constant] X # 144| 1: [ReservedWord] :: # 144| 2: [Identifier] baz @@ -367,7 +364,7 @@ calls/calls.rb: # 150| 1: [KeywordParameter] KeywordParameter # 150| 0: [Identifier] keyword # 150| 1: [ReservedWord] : -# 150| 2: [ScopeResolution] ScopeResolution +# 150| 2: [Call] Call # 150| 0: [Constant] X # 150| 1: [ReservedWord] :: # 150| 2: [Identifier] foo @@ -392,7 +389,7 @@ calls/calls.rb: # 156| 1: [OptionalParameter] OptionalParameter # 156| 0: [Identifier] param # 156| 1: [ReservedWord] = -# 156| 2: [ScopeResolution] ScopeResolution +# 156| 2: [Call] Call # 156| 0: [Constant] X # 156| 1: [ReservedWord] :: # 156| 2: [Identifier] foo @@ -402,7 +399,7 @@ calls/calls.rb: # 160| 0: [ReservedWord] module # 160| 1: [Constant] SomeModule # 161| 2: [Identifier] foo -# 162| 3: [ScopeResolution] ScopeResolution +# 162| 3: [Call] Call # 162| 0: [Constant] X # 162| 1: [ReservedWord] :: # 162| 2: [Identifier] bar @@ -414,17 +411,17 @@ calls/calls.rb: # 166| 3: [ReservedWord] : # 166| 4: [Identifier] baz # 167| 48: [Conditional] Conditional -# 167| 0: [ScopeResolution] ScopeResolution +# 167| 0: [Call] Call # 167| 0: [Constant] X # 167| 1: [ReservedWord] :: # 167| 2: [Identifier] foo # 167| 1: [ReservedWord] ? -# 167| 2: [ScopeResolution] ScopeResolution +# 167| 2: [Call] Call # 167| 0: [Constant] X # 167| 1: [ReservedWord] :: # 167| 2: [Identifier] bar # 167| 3: [ReservedWord] : -# 167| 4: [ScopeResolution] ScopeResolution +# 167| 4: [Call] Call # 167| 0: [Constant] X # 167| 1: [ReservedWord] :: # 167| 2: [Identifier] baz @@ -444,29 +441,29 @@ calls/calls.rb: # 176| 4: [ReservedWord] end # 177| 50: [If] If # 177| 0: [ReservedWord] if -# 177| 1: [ScopeResolution] ScopeResolution +# 177| 1: [Call] Call # 177| 0: [Constant] X # 177| 1: [ReservedWord] :: # 177| 2: [Identifier] foo # 177| 2: [Then] Then -# 178| 0: [ScopeResolution] ScopeResolution +# 178| 0: [Call] Call # 178| 0: [Constant] X # 178| 1: [ReservedWord] :: # 178| 2: [Identifier] wibble # 179| 3: [Elsif] Elsif # 179| 0: [ReservedWord] elsif -# 179| 1: [ScopeResolution] ScopeResolution +# 179| 1: [Call] Call # 179| 0: [Constant] X # 179| 1: [ReservedWord] :: # 179| 2: [Identifier] bar # 179| 2: [Then] Then -# 180| 0: [ScopeResolution] ScopeResolution +# 180| 0: [Call] Call # 180| 0: [Constant] X # 180| 1: [ReservedWord] :: # 180| 2: [Identifier] wobble # 181| 3: [Else] Else # 181| 0: [ReservedWord] else -# 182| 1: [ScopeResolution] ScopeResolution +# 182| 1: [Call] Call # 182| 0: [Constant] X # 182| 1: [ReservedWord] :: # 182| 2: [Identifier] wabble @@ -476,12 +473,12 @@ calls/calls.rb: # 186| 1: [ReservedWord] if # 186| 2: [Identifier] foo # 187| 52: [IfModifier] IfModifier -# 187| 0: [ScopeResolution] ScopeResolution +# 187| 0: [Call] Call # 187| 0: [Constant] X # 187| 1: [ReservedWord] :: # 187| 2: [Identifier] bar # 187| 1: [ReservedWord] if -# 187| 2: [ScopeResolution] ScopeResolution +# 187| 2: [Call] Call # 187| 0: [Constant] X # 187| 1: [ReservedWord] :: # 187| 2: [Identifier] foo @@ -493,12 +490,12 @@ calls/calls.rb: # 192| 3: [ReservedWord] end # 193| 54: [Unless] Unless # 193| 0: [ReservedWord] unless -# 193| 1: [ScopeResolution] ScopeResolution +# 193| 1: [Call] Call # 193| 0: [Constant] X # 193| 1: [ReservedWord] :: # 193| 2: [Identifier] foo # 193| 2: [Then] Then -# 194| 0: [ScopeResolution] ScopeResolution +# 194| 0: [Call] Call # 194| 0: [Constant] X # 194| 1: [ReservedWord] :: # 194| 2: [Identifier] bar @@ -508,12 +505,12 @@ calls/calls.rb: # 198| 1: [ReservedWord] unless # 198| 2: [Identifier] foo # 199| 56: [UnlessModifier] UnlessModifier -# 199| 0: [ScopeResolution] ScopeResolution +# 199| 0: [Call] Call # 199| 0: [Constant] X # 199| 1: [ReservedWord] :: # 199| 2: [Identifier] bar # 199| 1: [ReservedWord] unless -# 199| 2: [ScopeResolution] ScopeResolution +# 199| 2: [Call] Call # 199| 0: [Constant] X # 199| 1: [ReservedWord] :: # 199| 2: [Identifier] foo @@ -526,13 +523,13 @@ calls/calls.rb: # 204| 2: [ReservedWord] end # 205| 58: [While] While # 205| 0: [ReservedWord] while -# 205| 1: [ScopeResolution] ScopeResolution +# 205| 1: [Call] Call # 205| 0: [Constant] X # 205| 1: [ReservedWord] :: # 205| 2: [Identifier] foo # 205| 2: [Do] Do # 205| 0: [ReservedWord] do -# 206| 1: [ScopeResolution] ScopeResolution +# 206| 1: [Call] Call # 206| 0: [Constant] X # 206| 1: [ReservedWord] :: # 206| 2: [Identifier] bar @@ -542,12 +539,12 @@ calls/calls.rb: # 210| 1: [ReservedWord] while # 210| 2: [Identifier] foo # 211| 60: [WhileModifier] WhileModifier -# 211| 0: [ScopeResolution] ScopeResolution +# 211| 0: [Call] Call # 211| 0: [Constant] X # 211| 1: [ReservedWord] :: # 211| 2: [Identifier] bar # 211| 1: [ReservedWord] while -# 211| 2: [ScopeResolution] ScopeResolution +# 211| 2: [Call] Call # 211| 0: [Constant] X # 211| 1: [ReservedWord] :: # 211| 2: [Identifier] foo @@ -560,13 +557,13 @@ calls/calls.rb: # 216| 2: [ReservedWord] end # 217| 62: [Until] Until # 217| 0: [ReservedWord] until -# 217| 1: [ScopeResolution] ScopeResolution +# 217| 1: [Call] Call # 217| 0: [Constant] X # 217| 1: [ReservedWord] :: # 217| 2: [Identifier] foo # 217| 2: [Do] Do # 217| 0: [ReservedWord] do -# 218| 1: [ScopeResolution] ScopeResolution +# 218| 1: [Call] Call # 218| 0: [Constant] X # 218| 1: [ReservedWord] :: # 218| 2: [Identifier] bar @@ -576,12 +573,12 @@ calls/calls.rb: # 222| 1: [ReservedWord] until # 222| 2: [Identifier] foo # 223| 64: [UntilModifier] UntilModifier -# 223| 0: [ScopeResolution] ScopeResolution +# 223| 0: [Call] Call # 223| 0: [Constant] X # 223| 1: [ReservedWord] :: # 223| 2: [Identifier] bar # 223| 1: [ReservedWord] until -# 223| 2: [ScopeResolution] ScopeResolution +# 223| 2: [Call] Call # 223| 0: [Constant] X # 223| 1: [ReservedWord] :: # 223| 2: [Identifier] foo @@ -599,12 +596,12 @@ calls/calls.rb: # 229| 1: [Identifier] x # 229| 2: [In] In # 229| 0: [ReservedWord] in -# 229| 1: [ScopeResolution] ScopeResolution +# 229| 1: [Call] Call # 229| 0: [Constant] X # 229| 1: [ReservedWord] :: # 229| 2: [Identifier] bar # 229| 3: [Do] Do -# 230| 0: [ScopeResolution] ScopeResolution +# 230| 0: [Call] Call # 230| 0: [Constant] X # 230| 1: [ReservedWord] :: # 230| 2: [Identifier] baz @@ -615,12 +612,12 @@ calls/calls.rb: # 234| 2: [Identifier] bar # 234| 3: [ReservedWord] ] # 235| 68: [ElementReference] ElementReference -# 235| 0: [ScopeResolution] ScopeResolution +# 235| 0: [Call] Call # 235| 0: [Constant] X # 235| 1: [ReservedWord] :: # 235| 2: [Identifier] foo # 235| 1: [ReservedWord] [ -# 235| 2: [ScopeResolution] ScopeResolution +# 235| 2: [Call] Call # 235| 0: [Constant] X # 235| 1: [ReservedWord] :: # 235| 2: [Identifier] bar @@ -635,7 +632,7 @@ calls/calls.rb: # 238| 3: [StringContent] - # 238| 4: [Interpolation] Interpolation # 238| 0: [ReservedWord] #{ -# 238| 1: [ScopeResolution] ScopeResolution +# 238| 1: [Call] Call # 238| 0: [Constant] X # 238| 1: [ReservedWord] :: # 238| 2: [Identifier] baz @@ -646,7 +643,7 @@ calls/calls.rb: # 241| 1: [ReservedWord] :: # 241| 2: [Constant] Bar # 242| 71: [ScopeResolution] ScopeResolution -# 242| 0: [ScopeResolution] ScopeResolution +# 242| 0: [Call] Call # 242| 0: [Constant] X # 242| 1: [ReservedWord] :: # 242| 2: [Identifier] foo @@ -657,12 +654,12 @@ calls/calls.rb: # 245| 1: [ReservedWord] .. # 245| 2: [Identifier] bar # 246| 73: [Range] Range -# 246| 0: [ScopeResolution] ScopeResolution +# 246| 0: [Call] Call # 246| 0: [Constant] X # 246| 1: [ReservedWord] :: # 246| 2: [Identifier] foo # 246| 1: [ReservedWord] .. -# 246| 2: [ScopeResolution] ScopeResolution +# 246| 2: [Call] Call # 246| 0: [Constant] X # 246| 1: [ReservedWord] :: # 246| 2: [Identifier] bar @@ -674,12 +671,12 @@ calls/calls.rb: # 249| 2: [Identifier] bar # 249| 2: [ReservedWord] , # 249| 3: [Pair] Pair -# 249| 0: [ScopeResolution] ScopeResolution +# 249| 0: [Call] Call # 249| 0: [Constant] X # 249| 1: [ReservedWord] :: # 249| 2: [Identifier] foo # 249| 1: [ReservedWord] => -# 249| 2: [ScopeResolution] ScopeResolution +# 249| 2: [Call] Call # 249| 0: [Constant] X # 249| 1: [ReservedWord] :: # 249| 2: [Identifier] bar @@ -699,13 +696,13 @@ calls/calls.rb: # 257| 1: [Rescue] Rescue # 257| 0: [ReservedWord] rescue # 257| 1: [Exceptions] Exceptions -# 257| 0: [ScopeResolution] ScopeResolution +# 257| 0: [Call] Call # 257| 0: [Constant] X # 257| 1: [ReservedWord] :: # 257| 2: [Identifier] foo # 258| 2: [Ensure] Ensure # 258| 0: [ReservedWord] ensure -# 258| 1: [ScopeResolution] ScopeResolution +# 258| 1: [Call] Call # 258| 0: [Constant] X # 258| 1: [ReservedWord] :: # 258| 2: [Identifier] bar @@ -715,12 +712,12 @@ calls/calls.rb: # 262| 1: [ReservedWord] rescue # 262| 2: [Identifier] bar # 263| 78: [RescueModifier] RescueModifier -# 263| 0: [ScopeResolution] ScopeResolution +# 263| 0: [Call] Call # 263| 0: [Constant] X # 263| 1: [ReservedWord] :: # 263| 2: [Identifier] foo # 263| 1: [ReservedWord] rescue -# 263| 2: [ScopeResolution] ScopeResolution +# 263| 2: [Call] Call # 263| 0: [Constant] X # 263| 1: [ReservedWord] :: # 263| 2: [Identifier] bar @@ -738,7 +735,7 @@ calls/calls.rb: # 267| 0: [ReservedWord] ( # 267| 1: [BlockArgument] BlockArgument # 267| 0: [ReservedWord] & -# 267| 1: [ScopeResolution] ScopeResolution +# 267| 1: [Call] Call # 267| 0: [Constant] X # 267| 1: [ReservedWord] :: # 267| 2: [Identifier] bar @@ -764,7 +761,7 @@ calls/calls.rb: # 271| 0: [ReservedWord] ( # 271| 1: [SplatArgument] SplatArgument # 271| 0: [ReservedWord] * -# 271| 1: [ScopeResolution] ScopeResolution +# 271| 1: [Call] Call # 271| 0: [Constant] X # 271| 1: [ReservedWord] :: # 271| 2: [Identifier] bar @@ -783,7 +780,7 @@ calls/calls.rb: # 275| 0: [ReservedWord] ( # 275| 1: [HashSplatArgument] HashSplatArgument # 275| 0: [ReservedWord] ** -# 275| 1: [ScopeResolution] ScopeResolution +# 275| 1: [Call] Call # 275| 0: [Constant] X # 275| 1: [ReservedWord] :: # 275| 2: [Identifier] bar @@ -804,7 +801,7 @@ calls/calls.rb: # 279| 1: [Pair] Pair # 279| 0: [HashKeySymbol] blah # 279| 1: [ReservedWord] : -# 279| 2: [ScopeResolution] ScopeResolution +# 279| 2: [Call] Call # 279| 0: [Constant] X # 279| 1: [ReservedWord] :: # 279| 2: [Identifier] bar @@ -2223,6 +2220,7 @@ control/cases.rb: # 100| 0: [ReservedWord] in # 100| 1: [AlternativePattern] AlternativePattern # 100| 0: [Nil] nil +# 100| 0: [ReservedWord] nil # 100| 1: [ReservedWord] | # 100| 2: [Self] self # 100| 3: [ReservedWord] | @@ -3656,11 +3654,12 @@ gems/test.gemspec: literals/literals.rb: # 1| [Program] Program # 2| 0: [Nil] nil -# 3| 1: [Nil] NIL +# 2| 0: [ReservedWord] nil +# 3| 1: [Constant] NIL # 4| 2: [False] false -# 5| 3: [False] FALSE +# 5| 3: [Constant] FALSE # 6| 4: [True] true -# 7| 5: [True] TRUE +# 7| 5: [Constant] TRUE # 10| 6: [Integer] 1234 # 11| 7: [Integer] 5_678 # 12| 8: [Integer] 0 @@ -3695,58 +3694,67 @@ literals/literals.rb: # 49| 35: [Rational] Rational # 49| 0: [Float] 9.85 # 49| 1: [ReservedWord] r -# 52| 36: [Complex] 2i -# 59| 37: [String] String +# 52| 36: [Complex] Complex +# 52| 0: [Integer] 2 +# 52| 1: [ReservedWord] i +# 53| 37: [Complex] Complex +# 53| 0: [Float] 3.14 +# 53| 1: [ReservedWord] i +# 56| 38: [Complex] Complex +# 56| 0: [Rational] Rational +# 56| 0: [Float] 1.2 +# 56| 1: [ReservedWord] ri +# 59| 39: [String] String # 59| 0: [ReservedWord] " # 59| 1: [ReservedWord] " -# 60| 38: [String] String +# 60| 40: [String] String # 60| 0: [ReservedWord] ' # 60| 1: [ReservedWord] ' -# 61| 39: [String] String +# 61| 41: [String] String # 61| 0: [ReservedWord] " # 61| 1: [StringContent] hello # 61| 2: [ReservedWord] " -# 62| 40: [String] String +# 62| 42: [String] String # 62| 0: [ReservedWord] ' # 62| 1: [StringContent] goodbye # 62| 2: [ReservedWord] ' -# 63| 41: [String] String +# 63| 43: [String] String # 63| 0: [ReservedWord] " # 63| 1: [StringContent] string with escaped # 63| 2: [EscapeSequence] \" # 63| 3: [StringContent] quote # 63| 4: [ReservedWord] " -# 64| 42: [String] String +# 64| 44: [String] String # 64| 0: [ReservedWord] ' # 64| 1: [StringContent] string with " quote # 64| 2: [ReservedWord] ' -# 65| 43: [String] String +# 65| 45: [String] String # 65| 0: [ReservedWord] %( # 65| 1: [StringContent] foo bar baz # 65| 2: [ReservedWord] ) -# 66| 44: [String] String +# 66| 46: [String] String # 66| 0: [ReservedWord] %q< # 66| 1: [StringContent] foo bar baz # 66| 2: [ReservedWord] > -# 67| 45: [String] String +# 67| 47: [String] String # 67| 0: [ReservedWord] %q( # 67| 1: [StringContent] foo ' bar " baz' # 67| 2: [ReservedWord] ) -# 68| 46: [String] String +# 68| 48: [String] String # 68| 0: [ReservedWord] %Q( # 68| 1: [StringContent] FOO ' BAR " BAZ' # 68| 2: [ReservedWord] ) -# 69| 47: [String] String +# 69| 49: [String] String # 69| 0: [ReservedWord] %q( # 69| 1: [StringContent] foo\ bar # 69| 2: [ReservedWord] ) -# 70| 48: [String] String +# 70| 50: [String] String # 70| 0: [ReservedWord] %Q( # 70| 1: [StringContent] foo # 70| 2: [EscapeSequence] \ # 70| 3: [StringContent] bar # 70| 4: [ReservedWord] ) -# 71| 49: [String] String +# 71| 51: [String] String # 71| 0: [ReservedWord] " # 71| 1: [StringContent] 2 + 2 = # 71| 2: [Interpolation] Interpolation @@ -3757,7 +3765,7 @@ literals/literals.rb: # 71| 2: [Integer] 2 # 71| 2: [ReservedWord] } # 71| 3: [ReservedWord] " -# 72| 50: [String] String +# 72| 52: [String] String # 72| 0: [ReservedWord] %Q( # 72| 1: [StringContent] 3 + 4 = # 72| 2: [Interpolation] Interpolation @@ -3768,15 +3776,15 @@ literals/literals.rb: # 72| 2: [Integer] 4 # 72| 2: [ReservedWord] } # 72| 3: [ReservedWord] ) -# 73| 51: [String] String +# 73| 53: [String] String # 73| 0: [ReservedWord] ' # 73| 1: [StringContent] 2 + 2 = #{ 2 + 2 } # 73| 2: [ReservedWord] ' -# 74| 52: [String] String +# 74| 54: [String] String # 74| 0: [ReservedWord] %q( # 74| 1: [StringContent] 3 + 4 = #{ 3 + 4 } # 74| 2: [ReservedWord] ) -# 75| 53: [ChainedString] ChainedString +# 75| 55: [ChainedString] ChainedString # 75| 0: [String] String # 75| 0: [ReservedWord] " # 75| 1: [StringContent] foo @@ -3789,7 +3797,7 @@ literals/literals.rb: # 75| 0: [ReservedWord] " # 75| 1: [StringContent] baz # 75| 2: [ReservedWord] " -# 76| 54: [ChainedString] ChainedString +# 76| 56: [ChainedString] ChainedString # 76| 0: [String] String # 76| 0: [ReservedWord] %q{ # 76| 1: [StringContent] foo @@ -3802,7 +3810,7 @@ literals/literals.rb: # 76| 0: [ReservedWord] ' # 76| 1: [StringContent] baz # 76| 2: [ReservedWord] ' -# 77| 55: [ChainedString] ChainedString +# 77| 57: [ChainedString] ChainedString # 77| 0: [String] String # 77| 0: [ReservedWord] " # 77| 1: [StringContent] foo @@ -3822,7 +3830,7 @@ literals/literals.rb: # 77| 0: [ReservedWord] ' # 77| 1: [StringContent] baz # 77| 2: [ReservedWord] ' -# 78| 56: [String] String +# 78| 58: [String] String # 78| 0: [ReservedWord] " # 78| 1: [StringContent] foo # 78| 2: [Interpolation] Interpolation @@ -3842,7 +3850,7 @@ literals/literals.rb: # 78| 2: [ReservedWord] } # 78| 3: [StringContent] qux # 78| 4: [ReservedWord] " -# 79| 57: [String] String +# 79| 59: [String] String # 79| 0: [ReservedWord] " # 79| 1: [StringContent] foo # 79| 2: [Interpolation] Interpolation @@ -3859,21 +3867,21 @@ literals/literals.rb: # 79| 2: [Integer] 9 # 79| 4: [ReservedWord] } # 79| 3: [ReservedWord] " -# 80| 58: [Assignment] Assignment +# 80| 60: [Assignment] Assignment # 80| 0: [Identifier] bar # 80| 1: [ReservedWord] = # 80| 2: [String] String # 80| 0: [ReservedWord] " # 80| 1: [StringContent] bar # 80| 2: [ReservedWord] " -# 81| 59: [Assignment] Assignment +# 81| 61: [Assignment] Assignment # 81| 0: [Constant] BAR # 81| 1: [ReservedWord] = # 81| 2: [String] String # 81| 0: [ReservedWord] " # 81| 1: [StringContent] bar # 81| 2: [ReservedWord] " -# 82| 60: [String] String +# 82| 62: [String] String # 82| 0: [ReservedWord] " # 82| 1: [StringContent] foo # 82| 2: [Interpolation] Interpolation @@ -3881,7 +3889,7 @@ literals/literals.rb: # 82| 1: [Identifier] bar # 82| 2: [ReservedWord] } # 82| 3: [ReservedWord] " -# 83| 61: [String] String +# 83| 63: [String] String # 83| 0: [ReservedWord] " # 83| 1: [StringContent] foo # 83| 2: [Interpolation] Interpolation @@ -3889,28 +3897,28 @@ literals/literals.rb: # 83| 1: [Constant] BAR # 83| 2: [ReservedWord] } # 83| 3: [ReservedWord] " -# 86| 62: [Character] ?x -# 87| 63: [Character] ?\n -# 88| 64: [Character] ?\s -# 89| 65: [Character] ?\\ -# 90| 66: [Character] ?\u{58} -# 91| 67: [Character] ?\C-a -# 92| 68: [Character] ?\M-a -# 93| 69: [Character] ?\M-\C-a -# 94| 70: [Character] ?\C-\M-a -# 97| 71: [DelimitedSymbol] DelimitedSymbol +# 86| 64: [Character] ?x +# 87| 65: [Character] ?\n +# 88| 66: [Character] ?\s +# 89| 67: [Character] ?\\ +# 90| 68: [Character] ?\u{58} +# 91| 69: [Character] ?\C-a +# 92| 70: [Character] ?\M-a +# 93| 71: [Character] ?\M-\C-a +# 94| 72: [Character] ?\C-\M-a +# 97| 73: [DelimitedSymbol] DelimitedSymbol # 97| 0: [ReservedWord] :" # 97| 1: [ReservedWord] " -# 98| 72: [SimpleSymbol] :hello -# 99| 73: [DelimitedSymbol] DelimitedSymbol +# 98| 74: [SimpleSymbol] :hello +# 99| 75: [DelimitedSymbol] DelimitedSymbol # 99| 0: [ReservedWord] :" # 99| 1: [StringContent] foo bar # 99| 2: [ReservedWord] " -# 100| 74: [DelimitedSymbol] DelimitedSymbol +# 100| 76: [DelimitedSymbol] DelimitedSymbol # 100| 0: [ReservedWord] :' # 100| 1: [StringContent] bar baz # 100| 2: [ReservedWord] ' -# 101| 75: [Hash] Hash +# 101| 77: [Hash] Hash # 101| 0: [ReservedWord] { # 101| 1: [Pair] Pair # 101| 0: [HashKeySymbol] foo @@ -3920,15 +3928,15 @@ literals/literals.rb: # 101| 1: [StringContent] bar # 101| 2: [ReservedWord] " # 101| 2: [ReservedWord] } -# 102| 76: [DelimitedSymbol] DelimitedSymbol +# 102| 78: [DelimitedSymbol] DelimitedSymbol # 102| 0: [ReservedWord] %s( # 102| 1: [StringContent] wibble # 102| 2: [ReservedWord] ) -# 103| 77: [DelimitedSymbol] DelimitedSymbol +# 103| 79: [DelimitedSymbol] DelimitedSymbol # 103| 0: [ReservedWord] %s[ # 103| 1: [StringContent] wibble wobble # 103| 2: [ReservedWord] ] -# 104| 78: [DelimitedSymbol] DelimitedSymbol +# 104| 80: [DelimitedSymbol] DelimitedSymbol # 104| 0: [ReservedWord] :" # 104| 1: [StringContent] foo_ # 104| 2: [Interpolation] Interpolation @@ -3949,18 +3957,18 @@ literals/literals.rb: # 104| 1: [Constant] BAR # 104| 2: [ReservedWord] } # 104| 7: [ReservedWord] " -# 105| 79: [DelimitedSymbol] DelimitedSymbol +# 105| 81: [DelimitedSymbol] DelimitedSymbol # 105| 0: [ReservedWord] :' # 105| 1: [StringContent] foo_#{ 2 + 2}_#{bar}_#{BAR} # 105| 2: [ReservedWord] ' -# 106| 80: [DelimitedSymbol] DelimitedSymbol +# 106| 82: [DelimitedSymbol] DelimitedSymbol # 106| 0: [ReservedWord] %s( # 106| 1: [StringContent] foo_#{ 3 - 2 } # 106| 2: [ReservedWord] ) -# 109| 81: [Array] Array +# 109| 83: [Array] Array # 109| 0: [ReservedWord] [ # 109| 1: [ReservedWord] ] -# 110| 82: [Array] Array +# 110| 84: [Array] Array # 110| 0: [ReservedWord] [ # 110| 1: [Integer] 1 # 110| 2: [ReservedWord] , @@ -3968,7 +3976,7 @@ literals/literals.rb: # 110| 4: [ReservedWord] , # 110| 5: [Integer] 3 # 110| 6: [ReservedWord] ] -# 111| 83: [Array] Array +# 111| 85: [Array] Array # 111| 0: [ReservedWord] [ # 111| 1: [Integer] 4 # 111| 2: [ReservedWord] , @@ -3979,7 +3987,7 @@ literals/literals.rb: # 111| 1: [ReservedWord] / # 111| 2: [Integer] 2 # 111| 6: [ReservedWord] ] -# 112| 84: [Array] Array +# 112| 86: [Array] Array # 112| 0: [ReservedWord] [ # 112| 1: [Integer] 7 # 112| 2: [ReservedWord] , @@ -3990,10 +3998,10 @@ literals/literals.rb: # 112| 3: [Integer] 9 # 112| 4: [ReservedWord] ] # 112| 4: [ReservedWord] ] -# 115| 85: [StringArray] StringArray +# 115| 87: [StringArray] StringArray # 115| 0: [ReservedWord] %w( # 115| 1: [ReservedWord] ) -# 116| 86: [StringArray] StringArray +# 116| 88: [StringArray] StringArray # 116| 0: [ReservedWord] %w( # 116| 1: [BareString] BareString # 116| 0: [StringContent] foo @@ -4002,7 +4010,7 @@ literals/literals.rb: # 116| 3: [BareString] BareString # 116| 0: [StringContent] baz # 116| 4: [ReservedWord] ) -# 117| 87: [StringArray] StringArray +# 117| 89: [StringArray] StringArray # 117| 0: [ReservedWord] %w! # 117| 1: [BareString] BareString # 117| 0: [StringContent] foo @@ -4011,7 +4019,7 @@ literals/literals.rb: # 117| 3: [BareString] BareString # 117| 0: [StringContent] baz # 117| 4: [ReservedWord] ! -# 118| 88: [StringArray] StringArray +# 118| 90: [StringArray] StringArray # 118| 0: [ReservedWord] %W[ # 118| 1: [BareString] BareString # 118| 0: [StringContent] foo @@ -4037,7 +4045,7 @@ literals/literals.rb: # 118| 5: [BareString] BareString # 118| 0: [StringContent] baz # 118| 6: [ReservedWord] ] -# 119| 89: [StringArray] StringArray +# 119| 91: [StringArray] StringArray # 119| 0: [ReservedWord] %w[ # 119| 1: [BareString] BareString # 119| 0: [StringContent] foo @@ -4050,10 +4058,10 @@ literals/literals.rb: # 119| 5: [BareString] BareString # 119| 0: [StringContent] baz # 119| 6: [ReservedWord] ] -# 122| 90: [SymbolArray] SymbolArray +# 122| 92: [SymbolArray] SymbolArray # 122| 0: [ReservedWord] %i( # 122| 1: [ReservedWord] ) -# 123| 91: [SymbolArray] SymbolArray +# 123| 93: [SymbolArray] SymbolArray # 123| 0: [ReservedWord] %i( # 123| 1: [BareSymbol] BareSymbol # 123| 0: [StringContent] foo @@ -4062,7 +4070,7 @@ literals/literals.rb: # 123| 3: [BareSymbol] BareSymbol # 123| 0: [StringContent] baz # 123| 4: [ReservedWord] ) -# 124| 92: [SymbolArray] SymbolArray +# 124| 94: [SymbolArray] SymbolArray # 124| 0: [ReservedWord] %i@ # 124| 1: [BareSymbol] BareSymbol # 124| 0: [StringContent] foo @@ -4071,7 +4079,7 @@ literals/literals.rb: # 124| 3: [BareSymbol] BareSymbol # 124| 0: [StringContent] baz # 124| 4: [ReservedWord] @ -# 125| 93: [SymbolArray] SymbolArray +# 125| 95: [SymbolArray] SymbolArray # 125| 0: [ReservedWord] %I( # 125| 1: [BareSymbol] BareSymbol # 125| 0: [StringContent] foo @@ -4097,7 +4105,7 @@ literals/literals.rb: # 125| 5: [BareSymbol] BareSymbol # 125| 0: [StringContent] baz # 125| 6: [ReservedWord] ) -# 126| 94: [SymbolArray] SymbolArray +# 126| 96: [SymbolArray] SymbolArray # 126| 0: [ReservedWord] %i( # 126| 1: [BareSymbol] BareSymbol # 126| 0: [StringContent] foo @@ -4118,10 +4126,10 @@ literals/literals.rb: # 126| 9: [BareSymbol] BareSymbol # 126| 0: [StringContent] baz # 126| 10: [ReservedWord] ) -# 129| 95: [Hash] Hash +# 129| 97: [Hash] Hash # 129| 0: [ReservedWord] { # 129| 1: [ReservedWord] } -# 130| 96: [Hash] Hash +# 130| 98: [Hash] Hash # 130| 0: [ReservedWord] { # 130| 1: [Pair] Pair # 130| 0: [HashKeySymbol] foo @@ -4141,7 +4149,7 @@ literals/literals.rb: # 130| 1: [ReservedWord] => # 130| 2: [Integer] 3 # 130| 6: [ReservedWord] } -# 131| 97: [Hash] Hash +# 131| 99: [Hash] Hash # 131| 0: [ReservedWord] { # 131| 1: [Pair] Pair # 131| 0: [HashKeySymbol] foo @@ -4152,28 +4160,28 @@ literals/literals.rb: # 131| 0: [ReservedWord] ** # 131| 1: [Identifier] baz # 131| 4: [ReservedWord] } -# 134| 98: [ParenthesizedStatements] ParenthesizedStatements +# 134| 100: [ParenthesizedStatements] ParenthesizedStatements # 134| 0: [ReservedWord] ( # 134| 1: [Range] Range # 134| 0: [Integer] 1 # 134| 1: [ReservedWord] .. # 134| 2: [Integer] 10 # 134| 2: [ReservedWord] ) -# 135| 99: [ParenthesizedStatements] ParenthesizedStatements +# 135| 101: [ParenthesizedStatements] ParenthesizedStatements # 135| 0: [ReservedWord] ( # 135| 1: [Range] Range # 135| 0: [Integer] 1 # 135| 1: [ReservedWord] ... # 135| 2: [Integer] 10 # 135| 2: [ReservedWord] ) -# 136| 100: [ParenthesizedStatements] ParenthesizedStatements +# 136| 102: [ParenthesizedStatements] ParenthesizedStatements # 136| 0: [ReservedWord] ( # 136| 1: [Range] Range # 136| 0: [Integer] 1 # 136| 1: [ReservedWord] .. # 136| 2: [Integer] 0 # 136| 2: [ReservedWord] ) -# 137| 101: [ParenthesizedStatements] ParenthesizedStatements +# 137| 103: [ParenthesizedStatements] ParenthesizedStatements # 137| 0: [ReservedWord] ( # 137| 1: [Range] Range # 137| 0: [Identifier] start @@ -4183,36 +4191,36 @@ literals/literals.rb: # 137| 1: [ReservedWord] + # 137| 2: [Integer] 3 # 137| 2: [ReservedWord] ) -# 138| 102: [ParenthesizedStatements] ParenthesizedStatements +# 138| 104: [ParenthesizedStatements] ParenthesizedStatements # 138| 0: [ReservedWord] ( # 138| 1: [Range] Range # 138| 0: [Integer] 1 # 138| 1: [ReservedWord] .. # 138| 2: [ReservedWord] ) -# 139| 103: [ParenthesizedStatements] ParenthesizedStatements +# 139| 105: [ParenthesizedStatements] ParenthesizedStatements # 139| 0: [ReservedWord] ( # 139| 1: [Range] Range # 139| 0: [ReservedWord] .. # 139| 1: [Integer] 1 # 139| 2: [ReservedWord] ) -# 140| 104: [ParenthesizedStatements] ParenthesizedStatements +# 140| 106: [ParenthesizedStatements] ParenthesizedStatements # 140| 0: [ReservedWord] ( -# 140| 1: [Binary] Binary -# 140| 0: [Range] Range -# 140| 0: [Integer] 0 -# 140| 1: [ReservedWord] .. -# 140| 1: [ReservedWord] - -# 140| 2: [Integer] 1 +# 140| 1: [Range] Range +# 140| 0: [Integer] 0 +# 140| 1: [ReservedWord] .. +# 140| 2: [Unary] Unary +# 140| 0: [ReservedWord] - +# 140| 1: [Integer] 1 # 140| 2: [ReservedWord] ) -# 143| 105: [Subshell] Subshell +# 143| 107: [Subshell] Subshell # 143| 0: [ReservedWord] ` # 143| 1: [StringContent] ls -l # 143| 2: [ReservedWord] ` -# 144| 106: [Subshell] Subshell +# 144| 108: [Subshell] Subshell # 144| 0: [ReservedWord] %x( # 144| 1: [StringContent] ls -l # 144| 2: [ReservedWord] ) -# 145| 107: [Subshell] Subshell +# 145| 109: [Subshell] Subshell # 145| 0: [ReservedWord] ` # 145| 1: [StringContent] du -d # 145| 2: [Interpolation] Interpolation @@ -4233,7 +4241,7 @@ literals/literals.rb: # 145| 1: [Constant] BAR # 145| 2: [ReservedWord] } # 145| 7: [ReservedWord] ` -# 146| 108: [Subshell] Subshell +# 146| 110: [Subshell] Subshell # 146| 0: [ReservedWord] %x@ # 146| 1: [StringContent] du -d # 146| 2: [Interpolation] Interpolation @@ -4244,25 +4252,25 @@ literals/literals.rb: # 146| 2: [Integer] 4 # 146| 2: [ReservedWord] } # 146| 3: [ReservedWord] @ -# 149| 109: [Regex] Regex +# 149| 111: [Regex] Regex # 149| 0: [ReservedWord] / # 149| 1: [ReservedWord] / -# 150| 110: [Regex] Regex +# 150| 112: [Regex] Regex # 150| 0: [ReservedWord] / # 150| 1: [StringContent] foo # 150| 2: [ReservedWord] / -# 151| 111: [Regex] Regex +# 151| 113: [Regex] Regex # 151| 0: [ReservedWord] / # 151| 1: [StringContent] foo # 151| 2: [ReservedWord] /i -# 152| 112: [Regex] Regex +# 152| 114: [Regex] Regex # 152| 0: [ReservedWord] / # 152| 1: [StringContent] foo+ # 152| 2: [EscapeSequence] \s # 152| 3: [StringContent] bar # 152| 4: [EscapeSequence] \S # 152| 5: [ReservedWord] / -# 153| 113: [Regex] Regex +# 153| 115: [Regex] Regex # 153| 0: [ReservedWord] / # 153| 1: [StringContent] foo # 153| 2: [Interpolation] Interpolation @@ -4282,29 +4290,29 @@ literals/literals.rb: # 153| 1: [Constant] BAR # 153| 2: [ReservedWord] } # 153| 6: [ReservedWord] / -# 154| 114: [Regex] Regex +# 154| 116: [Regex] Regex # 154| 0: [ReservedWord] / # 154| 1: [StringContent] foo # 154| 2: [ReservedWord] /oxm -# 155| 115: [Regex] Regex +# 155| 117: [Regex] Regex # 155| 0: [ReservedWord] %r[ # 155| 1: [ReservedWord] ] -# 156| 116: [Regex] Regex +# 156| 118: [Regex] Regex # 156| 0: [ReservedWord] %r( # 156| 1: [StringContent] foo # 156| 2: [ReservedWord] ) -# 157| 117: [Regex] Regex +# 157| 119: [Regex] Regex # 157| 0: [ReservedWord] %r: # 157| 1: [StringContent] foo # 157| 2: [ReservedWord] :i -# 158| 118: [Regex] Regex +# 158| 120: [Regex] Regex # 158| 0: [ReservedWord] %r{ # 158| 1: [StringContent] foo+ # 158| 2: [EscapeSequence] \s # 158| 3: [StringContent] bar # 158| 4: [EscapeSequence] \S # 158| 5: [ReservedWord] } -# 159| 119: [Regex] Regex +# 159| 121: [Regex] Regex # 159| 0: [ReservedWord] %r{ # 159| 1: [StringContent] foo # 159| 2: [Interpolation] Interpolation @@ -4324,19 +4332,19 @@ literals/literals.rb: # 159| 1: [Constant] BAR # 159| 2: [ReservedWord] } # 159| 6: [ReservedWord] } -# 160| 120: [Regex] Regex +# 160| 122: [Regex] Regex # 160| 0: [ReservedWord] %r: # 160| 1: [StringContent] foo # 160| 2: [ReservedWord] :mxo -# 163| 121: [String] String +# 163| 123: [String] String # 163| 0: [ReservedWord] ' # 163| 1: [StringContent] abcdefghijklmnopqrstuvwxyzabcdef # 163| 2: [ReservedWord] ' -# 164| 122: [String] String +# 164| 124: [String] String # 164| 0: [ReservedWord] ' # 164| 1: [StringContent] foobarfoobarfoobarfoobarfoobarfoo # 164| 2: [ReservedWord] ' -# 165| 123: [String] String +# 165| 125: [String] String # 165| 0: [ReservedWord] " # 165| 1: [StringContent] foobar # 165| 2: [EscapeSequence] \\ @@ -4348,7 +4356,7 @@ literals/literals.rb: # 165| 8: [EscapeSequence] \\ # 165| 9: [StringContent] foobar # 165| 10: [ReservedWord] " -# 168| 124: [Call] Call +# 168| 126: [Call] Call # 168| 0: [Identifier] run_sql # 168| 1: [ArgumentList] ArgumentList # 168| 0: [ReservedWord] ( @@ -4356,7 +4364,7 @@ literals/literals.rb: # 168| 2: [ReservedWord] , # 168| 3: [HeredocBeginning] < | | literals.rb:139:4:139:4 | 1 | IntegerLiteral | 1 | | literals.rb:140:2:140:2 | 0 | IntegerLiteral | 0 | -| literals.rb:140:2:140:4 | _ .. _ | RangeLiteral | | +| literals.rb:140:2:140:6 | _ .. _ | RangeLiteral | | | literals.rb:140:6:140:6 | 1 | IntegerLiteral | 1 | | literals.rb:143:1:143:7 | `ls -l` | SubshellLiteral | ls -l | | literals.rb:144:1:144:9 | `ls -l` | SubshellLiteral | ls -l | @@ -767,18 +766,18 @@ finiteRangeLiterals | literals.rb:135:2:135:7 | _ ... _ | literals.rb:135:2:135:2 | 1 | literals.rb:135:6:135:7 | 10 | | literals.rb:136:2:136:7 | _ .. _ | literals.rb:136:2:136:2 | 1 | literals.rb:136:7:136:7 | 0 | | literals.rb:137:2:137:11 | _ .. _ | literals.rb:137:2:137:6 | call to start | literals.rb:137:9:137:11 | ... + ... | +| literals.rb:140:2:140:6 | _ .. _ | literals.rb:140:2:140:2 | 0 | literals.rb:140:5:140:6 | - ... | beginlessRangeLiterals | literals.rb:139:2:139:4 | _ .. _ | literals.rb:139:4:139:4 | 1 | endlessRangeLiterals | literals.rb:138:2:138:4 | _ .. _ | literals.rb:138:2:138:2 | 1 | -| literals.rb:140:2:140:4 | _ .. _ | literals.rb:140:2:140:2 | 0 | inclusiveRangeLiterals | literals.rb:134:2:134:6 | _ .. _ | | literals.rb:136:2:136:7 | _ .. _ | | literals.rb:137:2:137:11 | _ .. _ | | literals.rb:138:2:138:4 | _ .. _ | | literals.rb:139:2:139:4 | _ .. _ | -| literals.rb:140:2:140:4 | _ .. _ | +| literals.rb:140:2:140:6 | _ .. _ | exclusiveRangeLiterals | literals.rb:135:2:135:7 | _ ... _ | numericLiterals @@ -813,6 +812,8 @@ numericLiterals | literals.rb:48:1:48:3 | 23r | RationalLiteral | 23/1 | | literals.rb:49:1:49:5 | 9.85r | RationalLiteral | 985/100 | | literals.rb:52:1:52:2 | 2i | ComplexLiteral | 0+2i | +| literals.rb:53:1:53:5 | 3.14i | ComplexLiteral | 0+3.14i | +| literals.rb:56:1:56:5 | 1.2ri | ComplexLiteral | 0+1.2i | | literals.rb:71:13:71:13 | 2 | IntegerLiteral | 2 | | literals.rb:71:17:71:17 | 2 | IntegerLiteral | 2 | | literals.rb:72:15:72:15 | 3 | IntegerLiteral | 3 | @@ -952,3 +953,5 @@ rationalLiterals | literals.rb:49:1:49:5 | 9.85r | RationalLiteral | 985/100 | complexLiterals | literals.rb:52:1:52:2 | 2i | ComplexLiteral | 0+2i | +| literals.rb:53:1:53:5 | 3.14i | ComplexLiteral | 0+3.14i | +| literals.rb:56:1:56:5 | 1.2ri | ComplexLiteral | 0+1.2i | diff --git a/ruby/ql/test/library-tests/ast/literals/literals.rb b/ruby/ql/test/library-tests/ast/literals/literals.rb index 10c28de265f..6ddfc74e88f 100644 --- a/ruby/ql/test/library-tests/ast/literals/literals.rb +++ b/ruby/ql/test/library-tests/ast/literals/literals.rb @@ -50,10 +50,10 @@ TRUE # imaginary/complex numbers 2i -#3.14i # BAD: parse error +3.14i # imaginary & rational -#1.2ri # BAD: parse error +1.2ri # strings "" @@ -137,7 +137,7 @@ BAR = "bar" (start..2+3) (1..) # 1 to infinity (..1) # -infinity to 1 -(0..-1) # BAD: parsed as binary with minus endless range on the LHS +(0..-1) # subshell `ls -l` diff --git a/ruby/ql/test/library-tests/ast/params/params.expected b/ruby/ql/test/library-tests/ast/params/params.expected index afe41ce9cb8..a04d4393e40 100644 --- a/ruby/ql/test/library-tests/ast/params/params.expected +++ b/ruby/ql/test/library-tests/ast/params/params.expected @@ -36,6 +36,7 @@ idParams | params.rb:73:27:73:32 | wibble | wibble | | params.rb:77:16:77:18 | val | val | | params.rb:81:31:81:35 | array | array | +| params.rb:86:14:86:14 | x | x | blockParams | params.rb:46:28:46:33 | &block | block | | params.rb:62:29:62:34 | &block | block | @@ -103,6 +104,7 @@ paramsInBlocks | params.rb:65:25:67:3 | do ... end | 1 | params.rb:65:35:65:37 | age | OptionalParameter | | params.rb:77:12:78:3 | do ... end | 0 | params.rb:77:16:77:18 | val | SimpleParameter | | params.rb:77:12:78:3 | do ... end | 1 | params.rb:77:21:77:25 | **nil | HashSplatNilParameter | +| params.rb:86:11:86:31 | { ... } | 0 | params.rb:86:14:86:14 | x | SimpleParameter | paramsInLambdas | params.rb:14:7:14:33 | -> { ... } | 0 | params.rb:14:11:14:13 | foo | SimpleParameter | | params.rb:14:7:14:33 | -> { ... } | 1 | params.rb:14:16:14:18 | bar | SimpleParameter | @@ -162,3 +164,4 @@ params | params.rb:77:21:77:25 | **nil | 1 | HashSplatNilParameter | | params.rb:81:31:81:35 | array | 0 | SimpleParameter | | params.rb:81:38:81:38 | & | 1 | BlockParameter | +| params.rb:86:14:86:14 | x | 0 | SimpleParameter | diff --git a/ruby/ql/test/library-tests/ast/params/params.rb b/ruby/ql/test/library-tests/ast/params/params.rb index 2ba6b4aafda..c406d01009a 100644 --- a/ruby/ql/test/library-tests/ast/params/params.rb +++ b/ruby/ql/test/library-tests/ast/params/params.rb @@ -82,3 +82,5 @@ def anonymous_block_parameter(array, &) proc(&) array.each(&) end + +run_block { |x; y, z | puts x } diff --git a/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected b/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected index 0d18855a66c..fd7921fbd35 100644 --- a/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -2010,14 +2010,20 @@ cfg.rb: #-----| -> complex # 59| complex -#-----| -> 10-2i +#-----| -> 10 # 59| ... = ... #-----| -> conditional -# 59| 10-2i +# 59| 10 +#-----| -> 2i + +# 59| ... - ... #-----| -> ... = ... +# 59| 2i +#-----| -> ... - ... + # 60| conditional #-----| -> self @@ -3528,7 +3534,7 @@ cfg.rb: #-----| -> exit forward_param # 196| forward_param -#-----| -> exit cfg.rb (normal) +#-----| -> 1 # 196| a #-----| -> b @@ -3551,6 +3557,70 @@ cfg.rb: # 197| ... #-----| -> call to bar +# 200| 1 +#-----| -> { ... } + +# 200| call to times +#-----| -> 2 + +# 200| enter { ... } +#-----| -> a + +# 200| exit { ... } + +# 200| exit { ... } (normal) +#-----| -> exit { ... } + +# 200| { ... } +#-----| -> call to times + +# 200| a +#-----| -> b + +# 200| b +#-----| -> Kernel + +# 200| Kernel +#-----| -> a + +# 200| call to puts +#-----| -> exit { ... } (normal) + +# 200| a +#-----| -> call to puts + +# 202| 2 +#-----| -> do ... end + +# 202| call to times +#-----| -> exit cfg.rb (normal) + +# 202| do ... end +#-----| -> call to times + +# 202| enter do ... end +#-----| -> c + +# 202| exit do ... end + +# 202| exit do ... end (normal) +#-----| -> exit do ... end + +# 202| c +#-----| -> d + +# 202| d +#-----| -> Kernel + +# 202| Kernel +#-----| -> c + +# 202| call to puts +#-----| -> exit do ... end (normal) + +# 202| c +#-----| -> call to puts + desugar.rb: # 1| enter m1 #-----| -> x diff --git a/ruby/ql/test/library-tests/controlflow/graph/Nodes.expected b/ruby/ql/test/library-tests/controlflow/graph/Nodes.expected index 0aa6e18b345..73dfb482093 100644 --- a/ruby/ql/test/library-tests/controlflow/graph/Nodes.expected +++ b/ruby/ql/test/library-tests/controlflow/graph/Nodes.expected @@ -39,6 +39,8 @@ callsWithNoArguments | cfg.rb:167:5:167:10 | ! ... | | cfg.rb:168:5:168:8 | - ... | | cfg.rb:194:1:194:23 | call to run_block | +| cfg.rb:200:1:200:32 | call to times | +| cfg.rb:202:1:202:35 | call to times | | desugar.rb:6:3:6:7 | call to foo | | desugar.rb:10:3:10:7 | call to foo | | desugar.rb:14:3:14:7 | call to foo | @@ -122,6 +124,7 @@ positionalArguments | cfg.rb:49:8:49:13 | ... == ... | cfg.rb:49:13:49:13 | 0 | | cfg.rb:49:16:49:20 | ... > ... | cfg.rb:49:20:49:20 | 1 | | cfg.rb:49:27:49:37 | call to puts | cfg.rb:49:32:49:37 | "some" | +| cfg.rb:59:13:59:17 | ... - ... | cfg.rb:59:16:59:17 | 2i | | cfg.rb:60:17:60:22 | ... < ... | cfg.rb:60:21:60:22 | 10 | | cfg.rb:62:4:62:4 | call to [] | cfg.rb:62:4:62:4 | 0 | | cfg.rb:62:7:62:12 | call to [] | cfg.rb:62:7:62:12 | 1 | @@ -198,6 +201,8 @@ positionalArguments | cfg.rb:194:16:194:21 | call to puts | cfg.rb:194:21:194:21 | x | | cfg.rb:197:3:197:13 | call to bar | cfg.rb:197:7:197:7 | b | | cfg.rb:197:3:197:13 | call to bar | cfg.rb:197:10:197:12 | ... | +| cfg.rb:200:18:200:30 | call to puts | cfg.rb:200:30:200:30 | a | +| cfg.rb:202:19:202:31 | call to puts | cfg.rb:202:31:202:31 | c | | desugar.rb:2:5:2:6 | ... + ... | desugar.rb:2:8:2:8 | 1 | | desugar.rb:6:3:6:13 | call to count= | desugar.rb:6:17:6:17 | ... = ... | | desugar.rb:10:3:10:10 | call to []= | desugar.rb:10:9:10:9 | 0 | diff --git a/ruby/ql/test/library-tests/controlflow/graph/cfg.rb b/ruby/ql/test/library-tests/controlflow/graph/cfg.rb index 9876c735955..28cda8bc4ed 100644 --- a/ruby/ql/test/library-tests/controlflow/graph/cfg.rb +++ b/ruby/ql/test/library-tests/controlflow/graph/cfg.rb @@ -197,6 +197,10 @@ def forward_param(a, b, ...) bar(b, ...) end +1.times { |a; b| Kernel.puts a } + +2.times do |c; d| Kernel.puts c end + __END__ Some ignored nonsense diff --git a/ruby/ql/test/library-tests/variables/parameter.expected b/ruby/ql/test/library-tests/variables/parameter.expected index cd3a257a821..292ae665964 100644 --- a/ruby/ql/test/library-tests/variables/parameter.expected +++ b/ruby/ql/test/library-tests/variables/parameter.expected @@ -1,11 +1,9 @@ parameterVariable | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | | nested_scopes.rb:16:26:16:26 | x | nested_scopes.rb:16:26:16:26 | x | -| nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:29:16:29 | a | | nested_scopes.rb:18:26:18:26 | x | nested_scopes.rb:18:26:18:26 | x | | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | | parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | -| parameters.rb:1:18:1:18 | y | parameters.rb:1:18:1:18 | y | | parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | | parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | | parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map | From ccc18640dbb320f9872b0214270696178102001d Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Tue, 26 Apr 2022 11:04:26 +0200 Subject: [PATCH 105/171] Ruby: add upgrade and downgrade scripts --- .../old.dbscheme | 1417 +++++++++++++++++ .../ruby.dbscheme | 1393 ++++++++++++++++ .../ruby_block_parameters_child.ql | 14 + .../ruby_call_def.ql | 14 + .../ruby_rational_def.ql | 7 + .../ruby_tokeninfo.ql | 37 + .../upgrade.properties | 12 + .../old.dbscheme | 1393 ++++++++++++++++ .../ruby.dbscheme | 1417 +++++++++++++++++ .../ruby_ast_node_info.ql | 45 + .../ruby_block_parameters_child.ql | 29 + .../ruby_block_parameters_locals.ql | 23 + .../ruby_call_arguments.ql | 43 + .../ruby_call_def.ql | 27 + .../ruby_call_method.ql | 52 + .../ruby_call_operator.ql | 45 + .../ruby_call_receiver.ql | 43 + .../ruby_scope_resolution_def.ql | 16 + .../ruby_tokeninfo.ql | 20 + .../upgrade.properties | 12 + 20 files changed, 6059 insertions(+) create mode 100644 ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/old.dbscheme create mode 100644 ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby.dbscheme create mode 100644 ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_block_parameters_child.ql create mode 100644 ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_call_def.ql create mode 100644 ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_rational_def.ql create mode 100644 ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_tokeninfo.ql create mode 100644 ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/upgrade.properties create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/old.dbscheme create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby.dbscheme create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_ast_node_info.ql create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_block_parameters_child.ql create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_block_parameters_locals.ql create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_arguments.ql create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_def.ql create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_method.ql create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_operator.ql create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_receiver.ql create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_scope_resolution_def.ql create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_tokeninfo.ql create mode 100644 ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/upgrade.properties diff --git a/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/old.dbscheme b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/old.dbscheme new file mode 100644 index 00000000000..1199e154f5e --- /dev/null +++ b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/old.dbscheme @@ -0,0 +1,1417 @@ +// CodeQL database schema for Ruby +// Automatically generated from the tree-sitter grammar; do not edit + +@location = @location_default + +locations_default( + unique int id: @location_default, + int file: @file ref, + int start_line: int ref, + int start_column: int ref, + int end_line: int ref, + int end_column: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @file | @folder + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +sourceLocationPrefix( + string prefix: string ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +case @diagnostic.severity of + 10 = @diagnostic_debug +| 20 = @diagnostic_info +| 30 = @diagnostic_warning +| 40 = @diagnostic_error +; + + +@ruby_underscore_arg = @ruby_assignment | @ruby_binary | @ruby_conditional | @ruby_operator_assignment | @ruby_range | @ruby_unary | @ruby_underscore_primary + +@ruby_underscore_call_operator = @ruby_reserved_word + +@ruby_underscore_expression = @ruby_assignment | @ruby_binary | @ruby_break | @ruby_call | @ruby_next | @ruby_operator_assignment | @ruby_return | @ruby_unary | @ruby_underscore_arg | @ruby_yield + +@ruby_underscore_lhs = @ruby_call | @ruby_element_reference | @ruby_scope_resolution | @ruby_token_false | @ruby_token_nil | @ruby_token_true | @ruby_underscore_variable + +@ruby_underscore_method_name = @ruby_delimited_symbol | @ruby_setter | @ruby_token_constant | @ruby_token_identifier | @ruby_token_operator | @ruby_token_simple_symbol | @ruby_underscore_nonlocal_variable + +@ruby_underscore_nonlocal_variable = @ruby_token_class_variable | @ruby_token_global_variable | @ruby_token_instance_variable + +@ruby_underscore_pattern_constant = @ruby_scope_resolution | @ruby_token_constant + +@ruby_underscore_pattern_expr = @ruby_alternative_pattern | @ruby_as_pattern | @ruby_underscore_pattern_expr_basic + +@ruby_underscore_pattern_expr_basic = @ruby_array_pattern | @ruby_expression_reference_pattern | @ruby_find_pattern | @ruby_hash_pattern | @ruby_parenthesized_pattern | @ruby_range | @ruby_token_identifier | @ruby_underscore_pattern_constant | @ruby_underscore_pattern_primitive | @ruby_variable_reference_pattern + +@ruby_underscore_pattern_primitive = @ruby_delimited_symbol | @ruby_lambda | @ruby_regex | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_symbol_array | @ruby_token_encoding | @ruby_token_false | @ruby_token_file | @ruby_token_heredoc_beginning | @ruby_token_line | @ruby_token_nil | @ruby_token_self | @ruby_token_simple_symbol | @ruby_token_true | @ruby_unary | @ruby_underscore_simple_numeric + +@ruby_underscore_pattern_top_expr_body = @ruby_array_pattern | @ruby_find_pattern | @ruby_hash_pattern | @ruby_underscore_pattern_expr + +@ruby_underscore_primary = @ruby_array | @ruby_begin | @ruby_break | @ruby_call | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_delimited_symbol | @ruby_for | @ruby_hash | @ruby_if | @ruby_lambda | @ruby_method | @ruby_module | @ruby_next | @ruby_parenthesized_statements | @ruby_redo | @ruby_regex | @ruby_retry | @ruby_return | @ruby_singleton_class | @ruby_singleton_method | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_symbol_array | @ruby_token_character | @ruby_token_heredoc_beginning | @ruby_token_simple_symbol | @ruby_unary | @ruby_underscore_lhs | @ruby_underscore_simple_numeric | @ruby_unless | @ruby_until | @ruby_while | @ruby_yield + +@ruby_underscore_simple_numeric = @ruby_complex | @ruby_rational | @ruby_token_float | @ruby_token_integer + +@ruby_underscore_statement = @ruby_alias | @ruby_begin_block | @ruby_end_block | @ruby_if_modifier | @ruby_rescue_modifier | @ruby_undef | @ruby_underscore_expression | @ruby_unless_modifier | @ruby_until_modifier | @ruby_while_modifier + +@ruby_underscore_variable = @ruby_token_constant | @ruby_token_identifier | @ruby_token_self | @ruby_token_super | @ruby_underscore_nonlocal_variable + +ruby_alias_def( + unique int id: @ruby_alias, + int alias: @ruby_underscore_method_name ref, + int name: @ruby_underscore_method_name ref +); + +#keyset[ruby_alternative_pattern, index] +ruby_alternative_pattern_alternatives( + int ruby_alternative_pattern: @ruby_alternative_pattern ref, + int index: int ref, + unique int alternatives: @ruby_underscore_pattern_expr_basic ref +); + +ruby_alternative_pattern_def( + unique int id: @ruby_alternative_pattern +); + +@ruby_argument_list_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_argument_list, index] +ruby_argument_list_child( + int ruby_argument_list: @ruby_argument_list ref, + int index: int ref, + unique int child: @ruby_argument_list_child_type ref +); + +ruby_argument_list_def( + unique int id: @ruby_argument_list +); + +@ruby_array_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_array, index] +ruby_array_child( + int ruby_array: @ruby_array ref, + int index: int ref, + unique int child: @ruby_array_child_type ref +); + +ruby_array_def( + unique int id: @ruby_array +); + +ruby_array_pattern_class( + unique int ruby_array_pattern: @ruby_array_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_array_pattern_child_type = @ruby_splat_parameter | @ruby_underscore_pattern_expr + +#keyset[ruby_array_pattern, index] +ruby_array_pattern_child( + int ruby_array_pattern: @ruby_array_pattern ref, + int index: int ref, + unique int child: @ruby_array_pattern_child_type ref +); + +ruby_array_pattern_def( + unique int id: @ruby_array_pattern +); + +ruby_as_pattern_def( + unique int id: @ruby_as_pattern, + int name: @ruby_token_identifier ref, + int value: @ruby_underscore_pattern_expr ref +); + +@ruby_assignment_left_type = @ruby_left_assignment_list | @ruby_underscore_lhs + +@ruby_assignment_right_type = @ruby_rescue_modifier | @ruby_right_assignment_list | @ruby_splat_argument | @ruby_underscore_expression + +ruby_assignment_def( + unique int id: @ruby_assignment, + int left: @ruby_assignment_left_type ref, + int right: @ruby_assignment_right_type ref +); + +@ruby_bare_string_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_bare_string, index] +ruby_bare_string_child( + int ruby_bare_string: @ruby_bare_string ref, + int index: int ref, + unique int child: @ruby_bare_string_child_type ref +); + +ruby_bare_string_def( + unique int id: @ruby_bare_string +); + +@ruby_bare_symbol_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_bare_symbol, index] +ruby_bare_symbol_child( + int ruby_bare_symbol: @ruby_bare_symbol ref, + int index: int ref, + unique int child: @ruby_bare_symbol_child_type ref +); + +ruby_bare_symbol_def( + unique int id: @ruby_bare_symbol +); + +@ruby_begin_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_begin, index] +ruby_begin_child( + int ruby_begin: @ruby_begin ref, + int index: int ref, + unique int child: @ruby_begin_child_type ref +); + +ruby_begin_def( + unique int id: @ruby_begin +); + +@ruby_begin_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_begin_block, index] +ruby_begin_block_child( + int ruby_begin_block: @ruby_begin_block ref, + int index: int ref, + unique int child: @ruby_begin_block_child_type ref +); + +ruby_begin_block_def( + unique int id: @ruby_begin_block +); + +@ruby_binary_left_type = @ruby_underscore_expression | @ruby_underscore_simple_numeric + +case @ruby_binary.operator of + 0 = @ruby_binary_bangequal +| 1 = @ruby_binary_bangtilde +| 2 = @ruby_binary_percent +| 3 = @ruby_binary_ampersand +| 4 = @ruby_binary_ampersandampersand +| 5 = @ruby_binary_star +| 6 = @ruby_binary_starstar +| 7 = @ruby_binary_plus +| 8 = @ruby_binary_minus +| 9 = @ruby_binary_slash +| 10 = @ruby_binary_langle +| 11 = @ruby_binary_langlelangle +| 12 = @ruby_binary_langleequal +| 13 = @ruby_binary_langleequalrangle +| 14 = @ruby_binary_equalequal +| 15 = @ruby_binary_equalequalequal +| 16 = @ruby_binary_equaltilde +| 17 = @ruby_binary_rangle +| 18 = @ruby_binary_rangleequal +| 19 = @ruby_binary_ranglerangle +| 20 = @ruby_binary_caret +| 21 = @ruby_binary_and +| 22 = @ruby_binary_or +| 23 = @ruby_binary_pipe +| 24 = @ruby_binary_pipepipe +; + + +ruby_binary_def( + unique int id: @ruby_binary, + int left: @ruby_binary_left_type ref, + int operator: int ref, + int right: @ruby_underscore_expression ref +); + +ruby_block_parameters( + unique int ruby_block: @ruby_block ref, + unique int parameters: @ruby_block_parameters ref +); + +@ruby_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_block, index] +ruby_block_child( + int ruby_block: @ruby_block ref, + int index: int ref, + unique int child: @ruby_block_child_type ref +); + +ruby_block_def( + unique int id: @ruby_block +); + +ruby_block_argument_child( + unique int ruby_block_argument: @ruby_block_argument ref, + unique int child: @ruby_underscore_arg ref +); + +ruby_block_argument_def( + unique int id: @ruby_block_argument +); + +ruby_block_parameter_name( + unique int ruby_block_parameter: @ruby_block_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_block_parameter_def( + unique int id: @ruby_block_parameter +); + +#keyset[ruby_block_parameters, index] +ruby_block_parameters_locals( + int ruby_block_parameters: @ruby_block_parameters ref, + int index: int ref, + unique int locals: @ruby_token_identifier ref +); + +@ruby_block_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_block_parameters, index] +ruby_block_parameters_child( + int ruby_block_parameters: @ruby_block_parameters ref, + int index: int ref, + unique int child: @ruby_block_parameters_child_type ref +); + +ruby_block_parameters_def( + unique int id: @ruby_block_parameters +); + +ruby_break_child( + unique int ruby_break: @ruby_break ref, + unique int child: @ruby_argument_list ref +); + +ruby_break_def( + unique int id: @ruby_break +); + +ruby_call_arguments( + unique int ruby_call: @ruby_call ref, + unique int arguments: @ruby_argument_list ref +); + +@ruby_call_block_type = @ruby_block | @ruby_do_block + +ruby_call_block( + unique int ruby_call: @ruby_call ref, + unique int block: @ruby_call_block_type ref +); + +@ruby_call_method_type = @ruby_token_operator | @ruby_underscore_variable + +ruby_call_method( + unique int ruby_call: @ruby_call ref, + unique int method: @ruby_call_method_type ref +); + +ruby_call_operator( + unique int ruby_call: @ruby_call ref, + unique int operator: @ruby_underscore_call_operator ref +); + +ruby_call_receiver( + unique int ruby_call: @ruby_call ref, + unique int receiver: @ruby_underscore_primary ref +); + +ruby_call_def( + unique int id: @ruby_call +); + +ruby_case_value( + unique int ruby_case__: @ruby_case__ ref, + unique int value: @ruby_underscore_statement ref +); + +@ruby_case_child_type = @ruby_else | @ruby_when + +#keyset[ruby_case__, index] +ruby_case_child( + int ruby_case__: @ruby_case__ ref, + int index: int ref, + unique int child: @ruby_case_child_type ref +); + +ruby_case_def( + unique int id: @ruby_case__ +); + +#keyset[ruby_case_match, index] +ruby_case_match_clauses( + int ruby_case_match: @ruby_case_match ref, + int index: int ref, + unique int clauses: @ruby_in_clause ref +); + +ruby_case_match_else( + unique int ruby_case_match: @ruby_case_match ref, + unique int else: @ruby_else ref +); + +ruby_case_match_def( + unique int id: @ruby_case_match, + int value: @ruby_underscore_statement ref +); + +#keyset[ruby_chained_string, index] +ruby_chained_string_child( + int ruby_chained_string: @ruby_chained_string ref, + int index: int ref, + unique int child: @ruby_string__ ref +); + +ruby_chained_string_def( + unique int id: @ruby_chained_string +); + +@ruby_class_name_type = @ruby_scope_resolution | @ruby_token_constant + +ruby_class_superclass( + unique int ruby_class: @ruby_class ref, + unique int superclass: @ruby_superclass ref +); + +@ruby_class_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_class, index] +ruby_class_child( + int ruby_class: @ruby_class ref, + int index: int ref, + unique int child: @ruby_class_child_type ref +); + +ruby_class_def( + unique int id: @ruby_class, + int name: @ruby_class_name_type ref +); + +@ruby_complex_child_type = @ruby_rational | @ruby_token_float | @ruby_token_integer + +ruby_complex_def( + unique int id: @ruby_complex, + int child: @ruby_complex_child_type ref +); + +ruby_conditional_def( + unique int id: @ruby_conditional, + int alternative: @ruby_underscore_arg ref, + int condition: @ruby_underscore_arg ref, + int consequence: @ruby_underscore_arg ref +); + +@ruby_delimited_symbol_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_delimited_symbol, index] +ruby_delimited_symbol_child( + int ruby_delimited_symbol: @ruby_delimited_symbol ref, + int index: int ref, + unique int child: @ruby_delimited_symbol_child_type ref +); + +ruby_delimited_symbol_def( + unique int id: @ruby_delimited_symbol +); + +@ruby_destructured_left_assignment_child_type = @ruby_destructured_left_assignment | @ruby_rest_assignment | @ruby_underscore_lhs + +#keyset[ruby_destructured_left_assignment, index] +ruby_destructured_left_assignment_child( + int ruby_destructured_left_assignment: @ruby_destructured_left_assignment ref, + int index: int ref, + unique int child: @ruby_destructured_left_assignment_child_type ref +); + +ruby_destructured_left_assignment_def( + unique int id: @ruby_destructured_left_assignment +); + +@ruby_destructured_parameter_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_destructured_parameter, index] +ruby_destructured_parameter_child( + int ruby_destructured_parameter: @ruby_destructured_parameter ref, + int index: int ref, + unique int child: @ruby_destructured_parameter_child_type ref +); + +ruby_destructured_parameter_def( + unique int id: @ruby_destructured_parameter +); + +@ruby_do_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_do, index] +ruby_do_child( + int ruby_do: @ruby_do ref, + int index: int ref, + unique int child: @ruby_do_child_type ref +); + +ruby_do_def( + unique int id: @ruby_do +); + +ruby_do_block_parameters( + unique int ruby_do_block: @ruby_do_block ref, + unique int parameters: @ruby_block_parameters ref +); + +@ruby_do_block_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_do_block, index] +ruby_do_block_child( + int ruby_do_block: @ruby_do_block ref, + int index: int ref, + unique int child: @ruby_do_block_child_type ref +); + +ruby_do_block_def( + unique int id: @ruby_do_block +); + +@ruby_element_reference_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_element_reference, index] +ruby_element_reference_child( + int ruby_element_reference: @ruby_element_reference ref, + int index: int ref, + unique int child: @ruby_element_reference_child_type ref +); + +ruby_element_reference_def( + unique int id: @ruby_element_reference, + int object: @ruby_underscore_primary ref +); + +@ruby_else_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_else, index] +ruby_else_child( + int ruby_else: @ruby_else ref, + int index: int ref, + unique int child: @ruby_else_child_type ref +); + +ruby_else_def( + unique int id: @ruby_else +); + +@ruby_elsif_alternative_type = @ruby_else | @ruby_elsif + +ruby_elsif_alternative( + unique int ruby_elsif: @ruby_elsif ref, + unique int alternative: @ruby_elsif_alternative_type ref +); + +ruby_elsif_consequence( + unique int ruby_elsif: @ruby_elsif ref, + unique int consequence: @ruby_then ref +); + +ruby_elsif_def( + unique int id: @ruby_elsif, + int condition: @ruby_underscore_statement ref +); + +@ruby_end_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_end_block, index] +ruby_end_block_child( + int ruby_end_block: @ruby_end_block ref, + int index: int ref, + unique int child: @ruby_end_block_child_type ref +); + +ruby_end_block_def( + unique int id: @ruby_end_block +); + +@ruby_ensure_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_ensure, index] +ruby_ensure_child( + int ruby_ensure: @ruby_ensure ref, + int index: int ref, + unique int child: @ruby_ensure_child_type ref +); + +ruby_ensure_def( + unique int id: @ruby_ensure +); + +ruby_exception_variable_def( + unique int id: @ruby_exception_variable, + int child: @ruby_underscore_lhs ref +); + +@ruby_exceptions_child_type = @ruby_splat_argument | @ruby_underscore_arg + +#keyset[ruby_exceptions, index] +ruby_exceptions_child( + int ruby_exceptions: @ruby_exceptions ref, + int index: int ref, + unique int child: @ruby_exceptions_child_type ref +); + +ruby_exceptions_def( + unique int id: @ruby_exceptions +); + +ruby_expression_reference_pattern_def( + unique int id: @ruby_expression_reference_pattern, + int value: @ruby_underscore_expression ref +); + +ruby_find_pattern_class( + unique int ruby_find_pattern: @ruby_find_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_find_pattern_child_type = @ruby_splat_parameter | @ruby_underscore_pattern_expr + +#keyset[ruby_find_pattern, index] +ruby_find_pattern_child( + int ruby_find_pattern: @ruby_find_pattern ref, + int index: int ref, + unique int child: @ruby_find_pattern_child_type ref +); + +ruby_find_pattern_def( + unique int id: @ruby_find_pattern +); + +@ruby_for_pattern_type = @ruby_left_assignment_list | @ruby_underscore_lhs + +ruby_for_def( + unique int id: @ruby_for, + int body: @ruby_do ref, + int pattern: @ruby_for_pattern_type ref, + int value: @ruby_in ref +); + +@ruby_hash_child_type = @ruby_hash_splat_argument | @ruby_pair + +#keyset[ruby_hash, index] +ruby_hash_child( + int ruby_hash: @ruby_hash ref, + int index: int ref, + unique int child: @ruby_hash_child_type ref +); + +ruby_hash_def( + unique int id: @ruby_hash +); + +ruby_hash_pattern_class( + unique int ruby_hash_pattern: @ruby_hash_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_hash_pattern_child_type = @ruby_hash_splat_parameter | @ruby_keyword_pattern | @ruby_token_hash_splat_nil + +#keyset[ruby_hash_pattern, index] +ruby_hash_pattern_child( + int ruby_hash_pattern: @ruby_hash_pattern ref, + int index: int ref, + unique int child: @ruby_hash_pattern_child_type ref +); + +ruby_hash_pattern_def( + unique int id: @ruby_hash_pattern +); + +ruby_hash_splat_argument_def( + unique int id: @ruby_hash_splat_argument, + int child: @ruby_underscore_arg ref +); + +ruby_hash_splat_parameter_name( + unique int ruby_hash_splat_parameter: @ruby_hash_splat_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_hash_splat_parameter_def( + unique int id: @ruby_hash_splat_parameter +); + +@ruby_heredoc_body_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_heredoc_content | @ruby_token_heredoc_end + +#keyset[ruby_heredoc_body, index] +ruby_heredoc_body_child( + int ruby_heredoc_body: @ruby_heredoc_body ref, + int index: int ref, + unique int child: @ruby_heredoc_body_child_type ref +); + +ruby_heredoc_body_def( + unique int id: @ruby_heredoc_body +); + +@ruby_if_alternative_type = @ruby_else | @ruby_elsif + +ruby_if_alternative( + unique int ruby_if: @ruby_if ref, + unique int alternative: @ruby_if_alternative_type ref +); + +ruby_if_consequence( + unique int ruby_if: @ruby_if ref, + unique int consequence: @ruby_then ref +); + +ruby_if_def( + unique int id: @ruby_if, + int condition: @ruby_underscore_statement ref +); + +ruby_if_guard_def( + unique int id: @ruby_if_guard, + int condition: @ruby_underscore_expression ref +); + +ruby_if_modifier_def( + unique int id: @ruby_if_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_in_def( + unique int id: @ruby_in, + int child: @ruby_underscore_arg ref +); + +ruby_in_clause_body( + unique int ruby_in_clause: @ruby_in_clause ref, + unique int body: @ruby_then ref +); + +@ruby_in_clause_guard_type = @ruby_if_guard | @ruby_unless_guard + +ruby_in_clause_guard( + unique int ruby_in_clause: @ruby_in_clause ref, + unique int guard: @ruby_in_clause_guard_type ref +); + +ruby_in_clause_def( + unique int id: @ruby_in_clause, + int pattern: @ruby_underscore_pattern_top_expr_body ref +); + +@ruby_interpolation_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_interpolation, index] +ruby_interpolation_child( + int ruby_interpolation: @ruby_interpolation ref, + int index: int ref, + unique int child: @ruby_interpolation_child_type ref +); + +ruby_interpolation_def( + unique int id: @ruby_interpolation +); + +ruby_keyword_parameter_value( + unique int ruby_keyword_parameter: @ruby_keyword_parameter ref, + unique int value: @ruby_underscore_arg ref +); + +ruby_keyword_parameter_def( + unique int id: @ruby_keyword_parameter, + int name: @ruby_token_identifier ref +); + +@ruby_keyword_pattern_key_type = @ruby_string__ | @ruby_token_hash_key_symbol + +ruby_keyword_pattern_value( + unique int ruby_keyword_pattern: @ruby_keyword_pattern ref, + unique int value: @ruby_underscore_pattern_expr ref +); + +ruby_keyword_pattern_def( + unique int id: @ruby_keyword_pattern, + int key__: @ruby_keyword_pattern_key_type ref +); + +@ruby_lambda_body_type = @ruby_block | @ruby_do_block + +ruby_lambda_parameters( + unique int ruby_lambda: @ruby_lambda ref, + unique int parameters: @ruby_lambda_parameters ref +); + +ruby_lambda_def( + unique int id: @ruby_lambda, + int body: @ruby_lambda_body_type ref +); + +@ruby_lambda_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_lambda_parameters, index] +ruby_lambda_parameters_child( + int ruby_lambda_parameters: @ruby_lambda_parameters ref, + int index: int ref, + unique int child: @ruby_lambda_parameters_child_type ref +); + +ruby_lambda_parameters_def( + unique int id: @ruby_lambda_parameters +); + +@ruby_left_assignment_list_child_type = @ruby_destructured_left_assignment | @ruby_rest_assignment | @ruby_underscore_lhs + +#keyset[ruby_left_assignment_list, index] +ruby_left_assignment_list_child( + int ruby_left_assignment_list: @ruby_left_assignment_list ref, + int index: int ref, + unique int child: @ruby_left_assignment_list_child_type ref +); + +ruby_left_assignment_list_def( + unique int id: @ruby_left_assignment_list +); + +ruby_method_parameters( + unique int ruby_method: @ruby_method ref, + unique int parameters: @ruby_method_parameters ref +); + +@ruby_method_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_arg | @ruby_underscore_statement + +#keyset[ruby_method, index] +ruby_method_child( + int ruby_method: @ruby_method ref, + int index: int ref, + unique int child: @ruby_method_child_type ref +); + +ruby_method_def( + unique int id: @ruby_method, + int name: @ruby_underscore_method_name ref +); + +@ruby_method_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_method_parameters, index] +ruby_method_parameters_child( + int ruby_method_parameters: @ruby_method_parameters ref, + int index: int ref, + unique int child: @ruby_method_parameters_child_type ref +); + +ruby_method_parameters_def( + unique int id: @ruby_method_parameters +); + +@ruby_module_name_type = @ruby_scope_resolution | @ruby_token_constant + +@ruby_module_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_module, index] +ruby_module_child( + int ruby_module: @ruby_module ref, + int index: int ref, + unique int child: @ruby_module_child_type ref +); + +ruby_module_def( + unique int id: @ruby_module, + int name: @ruby_module_name_type ref +); + +ruby_next_child( + unique int ruby_next: @ruby_next ref, + unique int child: @ruby_argument_list ref +); + +ruby_next_def( + unique int id: @ruby_next +); + +case @ruby_operator_assignment.operator of + 0 = @ruby_operator_assignment_percentequal +| 1 = @ruby_operator_assignment_ampersandampersandequal +| 2 = @ruby_operator_assignment_ampersandequal +| 3 = @ruby_operator_assignment_starstarequal +| 4 = @ruby_operator_assignment_starequal +| 5 = @ruby_operator_assignment_plusequal +| 6 = @ruby_operator_assignment_minusequal +| 7 = @ruby_operator_assignment_slashequal +| 8 = @ruby_operator_assignment_langlelangleequal +| 9 = @ruby_operator_assignment_ranglerangleequal +| 10 = @ruby_operator_assignment_caretequal +| 11 = @ruby_operator_assignment_pipeequal +| 12 = @ruby_operator_assignment_pipepipeequal +; + + +@ruby_operator_assignment_right_type = @ruby_rescue_modifier | @ruby_underscore_expression + +ruby_operator_assignment_def( + unique int id: @ruby_operator_assignment, + int left: @ruby_underscore_lhs ref, + int operator: int ref, + int right: @ruby_operator_assignment_right_type ref +); + +ruby_optional_parameter_def( + unique int id: @ruby_optional_parameter, + int name: @ruby_token_identifier ref, + int value: @ruby_underscore_arg ref +); + +@ruby_pair_key_type = @ruby_string__ | @ruby_token_hash_key_symbol | @ruby_underscore_arg + +ruby_pair_value( + unique int ruby_pair: @ruby_pair ref, + unique int value: @ruby_underscore_arg ref +); + +ruby_pair_def( + unique int id: @ruby_pair, + int key__: @ruby_pair_key_type ref +); + +ruby_parenthesized_pattern_def( + unique int id: @ruby_parenthesized_pattern, + int child: @ruby_underscore_pattern_expr ref +); + +@ruby_parenthesized_statements_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_parenthesized_statements, index] +ruby_parenthesized_statements_child( + int ruby_parenthesized_statements: @ruby_parenthesized_statements ref, + int index: int ref, + unique int child: @ruby_parenthesized_statements_child_type ref +); + +ruby_parenthesized_statements_def( + unique int id: @ruby_parenthesized_statements +); + +@ruby_pattern_child_type = @ruby_splat_argument | @ruby_underscore_arg + +ruby_pattern_def( + unique int id: @ruby_pattern, + int child: @ruby_pattern_child_type ref +); + +@ruby_program_child_type = @ruby_token_empty_statement | @ruby_token_uninterpreted | @ruby_underscore_statement + +#keyset[ruby_program, index] +ruby_program_child( + int ruby_program: @ruby_program ref, + int index: int ref, + unique int child: @ruby_program_child_type ref +); + +ruby_program_def( + unique int id: @ruby_program +); + +@ruby_range_begin_type = @ruby_underscore_arg | @ruby_underscore_pattern_primitive + +ruby_range_begin( + unique int ruby_range: @ruby_range ref, + unique int begin: @ruby_range_begin_type ref +); + +@ruby_range_end_type = @ruby_underscore_arg | @ruby_underscore_pattern_primitive + +ruby_range_end( + unique int ruby_range: @ruby_range ref, + unique int end: @ruby_range_end_type ref +); + +case @ruby_range.operator of + 0 = @ruby_range_dotdot +| 1 = @ruby_range_dotdotdot +; + + +ruby_range_def( + unique int id: @ruby_range, + int operator: int ref +); + +@ruby_rational_child_type = @ruby_token_float | @ruby_token_integer + +ruby_rational_def( + unique int id: @ruby_rational, + int child: @ruby_rational_child_type ref +); + +ruby_redo_child( + unique int ruby_redo: @ruby_redo ref, + unique int child: @ruby_argument_list ref +); + +ruby_redo_def( + unique int id: @ruby_redo +); + +@ruby_regex_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_regex, index] +ruby_regex_child( + int ruby_regex: @ruby_regex ref, + int index: int ref, + unique int child: @ruby_regex_child_type ref +); + +ruby_regex_def( + unique int id: @ruby_regex +); + +ruby_rescue_body( + unique int ruby_rescue: @ruby_rescue ref, + unique int body: @ruby_then ref +); + +ruby_rescue_exceptions( + unique int ruby_rescue: @ruby_rescue ref, + unique int exceptions: @ruby_exceptions ref +); + +ruby_rescue_variable( + unique int ruby_rescue: @ruby_rescue ref, + unique int variable: @ruby_exception_variable ref +); + +ruby_rescue_def( + unique int id: @ruby_rescue +); + +@ruby_rescue_modifier_body_type = @ruby_underscore_arg | @ruby_underscore_statement + +ruby_rescue_modifier_def( + unique int id: @ruby_rescue_modifier, + int body: @ruby_rescue_modifier_body_type ref, + int handler: @ruby_underscore_expression ref +); + +ruby_rest_assignment_child( + unique int ruby_rest_assignment: @ruby_rest_assignment ref, + unique int child: @ruby_underscore_lhs ref +); + +ruby_rest_assignment_def( + unique int id: @ruby_rest_assignment +); + +ruby_retry_child( + unique int ruby_retry: @ruby_retry ref, + unique int child: @ruby_argument_list ref +); + +ruby_retry_def( + unique int id: @ruby_retry +); + +ruby_return_child( + unique int ruby_return: @ruby_return ref, + unique int child: @ruby_argument_list ref +); + +ruby_return_def( + unique int id: @ruby_return +); + +@ruby_right_assignment_list_child_type = @ruby_splat_argument | @ruby_underscore_arg + +#keyset[ruby_right_assignment_list, index] +ruby_right_assignment_list_child( + int ruby_right_assignment_list: @ruby_right_assignment_list ref, + int index: int ref, + unique int child: @ruby_right_assignment_list_child_type ref +); + +ruby_right_assignment_list_def( + unique int id: @ruby_right_assignment_list +); + +@ruby_scope_resolution_scope_type = @ruby_underscore_pattern_constant | @ruby_underscore_primary + +ruby_scope_resolution_scope( + unique int ruby_scope_resolution: @ruby_scope_resolution ref, + unique int scope: @ruby_scope_resolution_scope_type ref +); + +ruby_scope_resolution_def( + unique int id: @ruby_scope_resolution, + int name: @ruby_token_constant ref +); + +ruby_setter_def( + unique int id: @ruby_setter, + int name: @ruby_token_identifier ref +); + +@ruby_singleton_class_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_singleton_class, index] +ruby_singleton_class_child( + int ruby_singleton_class: @ruby_singleton_class ref, + int index: int ref, + unique int child: @ruby_singleton_class_child_type ref +); + +ruby_singleton_class_def( + unique int id: @ruby_singleton_class, + int value: @ruby_underscore_arg ref +); + +@ruby_singleton_method_object_type = @ruby_underscore_arg | @ruby_underscore_variable + +ruby_singleton_method_parameters( + unique int ruby_singleton_method: @ruby_singleton_method ref, + unique int parameters: @ruby_method_parameters ref +); + +@ruby_singleton_method_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_arg | @ruby_underscore_statement + +#keyset[ruby_singleton_method, index] +ruby_singleton_method_child( + int ruby_singleton_method: @ruby_singleton_method ref, + int index: int ref, + unique int child: @ruby_singleton_method_child_type ref +); + +ruby_singleton_method_def( + unique int id: @ruby_singleton_method, + int name: @ruby_underscore_method_name ref, + int object: @ruby_singleton_method_object_type ref +); + +ruby_splat_argument_def( + unique int id: @ruby_splat_argument, + int child: @ruby_underscore_arg ref +); + +ruby_splat_parameter_name( + unique int ruby_splat_parameter: @ruby_splat_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_splat_parameter_def( + unique int id: @ruby_splat_parameter +); + +@ruby_string_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_string__, index] +ruby_string_child( + int ruby_string__: @ruby_string__ ref, + int index: int ref, + unique int child: @ruby_string_child_type ref +); + +ruby_string_def( + unique int id: @ruby_string__ +); + +#keyset[ruby_string_array, index] +ruby_string_array_child( + int ruby_string_array: @ruby_string_array ref, + int index: int ref, + unique int child: @ruby_bare_string ref +); + +ruby_string_array_def( + unique int id: @ruby_string_array +); + +@ruby_subshell_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_subshell, index] +ruby_subshell_child( + int ruby_subshell: @ruby_subshell ref, + int index: int ref, + unique int child: @ruby_subshell_child_type ref +); + +ruby_subshell_def( + unique int id: @ruby_subshell +); + +ruby_superclass_def( + unique int id: @ruby_superclass, + int child: @ruby_underscore_expression ref +); + +#keyset[ruby_symbol_array, index] +ruby_symbol_array_child( + int ruby_symbol_array: @ruby_symbol_array ref, + int index: int ref, + unique int child: @ruby_bare_symbol ref +); + +ruby_symbol_array_def( + unique int id: @ruby_symbol_array +); + +@ruby_then_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_then, index] +ruby_then_child( + int ruby_then: @ruby_then ref, + int index: int ref, + unique int child: @ruby_then_child_type ref +); + +ruby_then_def( + unique int id: @ruby_then +); + +@ruby_unary_operand_type = @ruby_parenthesized_statements | @ruby_underscore_expression | @ruby_underscore_simple_numeric + +case @ruby_unary.operator of + 0 = @ruby_unary_bang +| 1 = @ruby_unary_plus +| 2 = @ruby_unary_minus +| 3 = @ruby_unary_definedquestion +| 4 = @ruby_unary_not +| 5 = @ruby_unary_tilde +; + + +ruby_unary_def( + unique int id: @ruby_unary, + int operand: @ruby_unary_operand_type ref, + int operator: int ref +); + +#keyset[ruby_undef, index] +ruby_undef_child( + int ruby_undef: @ruby_undef ref, + int index: int ref, + unique int child: @ruby_underscore_method_name ref +); + +ruby_undef_def( + unique int id: @ruby_undef +); + +@ruby_unless_alternative_type = @ruby_else | @ruby_elsif + +ruby_unless_alternative( + unique int ruby_unless: @ruby_unless ref, + unique int alternative: @ruby_unless_alternative_type ref +); + +ruby_unless_consequence( + unique int ruby_unless: @ruby_unless ref, + unique int consequence: @ruby_then ref +); + +ruby_unless_def( + unique int id: @ruby_unless, + int condition: @ruby_underscore_statement ref +); + +ruby_unless_guard_def( + unique int id: @ruby_unless_guard, + int condition: @ruby_underscore_expression ref +); + +ruby_unless_modifier_def( + unique int id: @ruby_unless_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_until_def( + unique int id: @ruby_until, + int body: @ruby_do ref, + int condition: @ruby_underscore_statement ref +); + +ruby_until_modifier_def( + unique int id: @ruby_until_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +@ruby_variable_reference_pattern_name_type = @ruby_token_identifier | @ruby_underscore_nonlocal_variable + +ruby_variable_reference_pattern_def( + unique int id: @ruby_variable_reference_pattern, + int name: @ruby_variable_reference_pattern_name_type ref +); + +ruby_when_body( + unique int ruby_when: @ruby_when ref, + unique int body: @ruby_then ref +); + +#keyset[ruby_when, index] +ruby_when_pattern( + int ruby_when: @ruby_when ref, + int index: int ref, + unique int pattern: @ruby_pattern ref +); + +ruby_when_def( + unique int id: @ruby_when +); + +ruby_while_def( + unique int id: @ruby_while, + int body: @ruby_do ref, + int condition: @ruby_underscore_statement ref +); + +ruby_while_modifier_def( + unique int id: @ruby_while_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_yield_child( + unique int ruby_yield: @ruby_yield ref, + unique int child: @ruby_argument_list ref +); + +ruby_yield_def( + unique int id: @ruby_yield +); + +ruby_tokeninfo( + unique int id: @ruby_token, + int kind: int ref, + string value: string ref +); + +case @ruby_token.kind of + 0 = @ruby_reserved_word +| 1 = @ruby_token_character +| 2 = @ruby_token_class_variable +| 3 = @ruby_token_comment +| 4 = @ruby_token_constant +| 5 = @ruby_token_empty_statement +| 6 = @ruby_token_encoding +| 7 = @ruby_token_escape_sequence +| 8 = @ruby_token_false +| 9 = @ruby_token_file +| 10 = @ruby_token_float +| 11 = @ruby_token_forward_argument +| 12 = @ruby_token_forward_parameter +| 13 = @ruby_token_global_variable +| 14 = @ruby_token_hash_key_symbol +| 15 = @ruby_token_hash_splat_nil +| 16 = @ruby_token_heredoc_beginning +| 17 = @ruby_token_heredoc_content +| 18 = @ruby_token_heredoc_end +| 19 = @ruby_token_identifier +| 20 = @ruby_token_instance_variable +| 21 = @ruby_token_integer +| 22 = @ruby_token_line +| 23 = @ruby_token_nil +| 24 = @ruby_token_operator +| 25 = @ruby_token_self +| 26 = @ruby_token_simple_symbol +| 27 = @ruby_token_string_content +| 28 = @ruby_token_super +| 29 = @ruby_token_true +| 30 = @ruby_token_uninterpreted +; + + +@ruby_ast_node = @ruby_alias | @ruby_alternative_pattern | @ruby_argument_list | @ruby_array | @ruby_array_pattern | @ruby_as_pattern | @ruby_assignment | @ruby_bare_string | @ruby_bare_symbol | @ruby_begin | @ruby_begin_block | @ruby_binary | @ruby_block | @ruby_block_argument | @ruby_block_parameter | @ruby_block_parameters | @ruby_break | @ruby_call | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_complex | @ruby_conditional | @ruby_delimited_symbol | @ruby_destructured_left_assignment | @ruby_destructured_parameter | @ruby_do | @ruby_do_block | @ruby_element_reference | @ruby_else | @ruby_elsif | @ruby_end_block | @ruby_ensure | @ruby_exception_variable | @ruby_exceptions | @ruby_expression_reference_pattern | @ruby_find_pattern | @ruby_for | @ruby_hash | @ruby_hash_pattern | @ruby_hash_splat_argument | @ruby_hash_splat_parameter | @ruby_heredoc_body | @ruby_if | @ruby_if_guard | @ruby_if_modifier | @ruby_in | @ruby_in_clause | @ruby_interpolation | @ruby_keyword_parameter | @ruby_keyword_pattern | @ruby_lambda | @ruby_lambda_parameters | @ruby_left_assignment_list | @ruby_method | @ruby_method_parameters | @ruby_module | @ruby_next | @ruby_operator_assignment | @ruby_optional_parameter | @ruby_pair | @ruby_parenthesized_pattern | @ruby_parenthesized_statements | @ruby_pattern | @ruby_program | @ruby_range | @ruby_rational | @ruby_redo | @ruby_regex | @ruby_rescue | @ruby_rescue_modifier | @ruby_rest_assignment | @ruby_retry | @ruby_return | @ruby_right_assignment_list | @ruby_scope_resolution | @ruby_setter | @ruby_singleton_class | @ruby_singleton_method | @ruby_splat_argument | @ruby_splat_parameter | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_superclass | @ruby_symbol_array | @ruby_then | @ruby_token | @ruby_unary | @ruby_undef | @ruby_unless | @ruby_unless_guard | @ruby_unless_modifier | @ruby_until | @ruby_until_modifier | @ruby_variable_reference_pattern | @ruby_when | @ruby_while | @ruby_while_modifier | @ruby_yield + +@ruby_ast_node_parent = @file | @ruby_ast_node + +#keyset[parent, parent_index] +ruby_ast_node_info( + unique int node: @ruby_ast_node ref, + int parent: @ruby_ast_node_parent ref, + int parent_index: int ref, + int loc: @location ref +); + +erb_comment_directive_def( + unique int id: @erb_comment_directive, + int child: @erb_token_comment ref +); + +erb_directive_def( + unique int id: @erb_directive, + int child: @erb_token_code ref +); + +erb_graphql_directive_def( + unique int id: @erb_graphql_directive, + int child: @erb_token_code ref +); + +erb_output_directive_def( + unique int id: @erb_output_directive, + int child: @erb_token_code ref +); + +@erb_template_child_type = @erb_comment_directive | @erb_directive | @erb_graphql_directive | @erb_output_directive | @erb_token_content + +#keyset[erb_template, index] +erb_template_child( + int erb_template: @erb_template ref, + int index: int ref, + unique int child: @erb_template_child_type ref +); + +erb_template_def( + unique int id: @erb_template +); + +erb_tokeninfo( + unique int id: @erb_token, + int kind: int ref, + string value: string ref +); + +case @erb_token.kind of + 0 = @erb_reserved_word +| 1 = @erb_token_code +| 2 = @erb_token_comment +| 3 = @erb_token_content +; + + +@erb_ast_node = @erb_comment_directive | @erb_directive | @erb_graphql_directive | @erb_output_directive | @erb_template | @erb_token + +@erb_ast_node_parent = @erb_ast_node | @file + +#keyset[parent, parent_index] +erb_ast_node_info( + unique int node: @erb_ast_node ref, + int parent: @erb_ast_node_parent ref, + int parent_index: int ref, + int loc: @location ref +); + diff --git a/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby.dbscheme b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby.dbscheme new file mode 100644 index 00000000000..9fdd1d40fd3 --- /dev/null +++ b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby.dbscheme @@ -0,0 +1,1393 @@ +// CodeQL database schema for Ruby +// Automatically generated from the tree-sitter grammar; do not edit + +@location = @location_default + +locations_default( + unique int id: @location_default, + int file: @file ref, + int start_line: int ref, + int start_column: int ref, + int end_line: int ref, + int end_column: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @file | @folder + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +sourceLocationPrefix( + string prefix: string ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +case @diagnostic.severity of + 10 = @diagnostic_debug +| 20 = @diagnostic_info +| 30 = @diagnostic_warning +| 40 = @diagnostic_error +; + + +@ruby_underscore_arg = @ruby_assignment | @ruby_binary | @ruby_conditional | @ruby_operator_assignment | @ruby_range | @ruby_unary | @ruby_underscore_primary + +@ruby_underscore_expression = @ruby_assignment | @ruby_binary | @ruby_break | @ruby_call | @ruby_next | @ruby_operator_assignment | @ruby_return | @ruby_unary | @ruby_underscore_arg | @ruby_yield + +@ruby_underscore_lhs = @ruby_call | @ruby_element_reference | @ruby_scope_resolution | @ruby_token_false | @ruby_token_nil | @ruby_token_true | @ruby_underscore_variable + +@ruby_underscore_method_name = @ruby_delimited_symbol | @ruby_setter | @ruby_token_constant | @ruby_token_identifier | @ruby_token_operator | @ruby_token_simple_symbol | @ruby_underscore_nonlocal_variable + +@ruby_underscore_nonlocal_variable = @ruby_token_class_variable | @ruby_token_global_variable | @ruby_token_instance_variable + +@ruby_underscore_pattern_constant = @ruby_scope_resolution | @ruby_token_constant + +@ruby_underscore_pattern_expr = @ruby_alternative_pattern | @ruby_as_pattern | @ruby_underscore_pattern_expr_basic + +@ruby_underscore_pattern_expr_basic = @ruby_array_pattern | @ruby_expression_reference_pattern | @ruby_find_pattern | @ruby_hash_pattern | @ruby_parenthesized_pattern | @ruby_range | @ruby_token_identifier | @ruby_underscore_pattern_constant | @ruby_underscore_pattern_primitive | @ruby_variable_reference_pattern + +@ruby_underscore_pattern_primitive = @ruby_delimited_symbol | @ruby_lambda | @ruby_regex | @ruby_string__ | @ruby_string_array | @ruby_symbol_array | @ruby_token_encoding | @ruby_token_false | @ruby_token_file | @ruby_token_line | @ruby_token_nil | @ruby_token_self | @ruby_token_simple_symbol | @ruby_token_true | @ruby_unary | @ruby_underscore_simple_numeric + +@ruby_underscore_pattern_top_expr_body = @ruby_array_pattern | @ruby_find_pattern | @ruby_hash_pattern | @ruby_underscore_pattern_expr + +@ruby_underscore_primary = @ruby_array | @ruby_begin | @ruby_break | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_delimited_symbol | @ruby_for | @ruby_hash | @ruby_if | @ruby_lambda | @ruby_method | @ruby_module | @ruby_next | @ruby_parenthesized_statements | @ruby_redo | @ruby_regex | @ruby_retry | @ruby_return | @ruby_singleton_class | @ruby_singleton_method | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_symbol_array | @ruby_token_character | @ruby_token_heredoc_beginning | @ruby_token_simple_symbol | @ruby_unary | @ruby_underscore_lhs | @ruby_underscore_simple_numeric | @ruby_unless | @ruby_until | @ruby_while | @ruby_yield + +@ruby_underscore_simple_numeric = @ruby_rational | @ruby_token_complex | @ruby_token_float | @ruby_token_integer + +@ruby_underscore_statement = @ruby_alias | @ruby_begin_block | @ruby_end_block | @ruby_if_modifier | @ruby_rescue_modifier | @ruby_undef | @ruby_underscore_expression | @ruby_unless_modifier | @ruby_until_modifier | @ruby_while_modifier + +@ruby_underscore_variable = @ruby_token_constant | @ruby_token_identifier | @ruby_token_self | @ruby_token_super | @ruby_underscore_nonlocal_variable + +ruby_alias_def( + unique int id: @ruby_alias, + int alias: @ruby_underscore_method_name ref, + int name: @ruby_underscore_method_name ref +); + +#keyset[ruby_alternative_pattern, index] +ruby_alternative_pattern_alternatives( + int ruby_alternative_pattern: @ruby_alternative_pattern ref, + int index: int ref, + unique int alternatives: @ruby_underscore_pattern_expr_basic ref +); + +ruby_alternative_pattern_def( + unique int id: @ruby_alternative_pattern +); + +@ruby_argument_list_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_argument_list, index] +ruby_argument_list_child( + int ruby_argument_list: @ruby_argument_list ref, + int index: int ref, + unique int child: @ruby_argument_list_child_type ref +); + +ruby_argument_list_def( + unique int id: @ruby_argument_list +); + +@ruby_array_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_array, index] +ruby_array_child( + int ruby_array: @ruby_array ref, + int index: int ref, + unique int child: @ruby_array_child_type ref +); + +ruby_array_def( + unique int id: @ruby_array +); + +ruby_array_pattern_class( + unique int ruby_array_pattern: @ruby_array_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_array_pattern_child_type = @ruby_splat_parameter | @ruby_underscore_pattern_expr + +#keyset[ruby_array_pattern, index] +ruby_array_pattern_child( + int ruby_array_pattern: @ruby_array_pattern ref, + int index: int ref, + unique int child: @ruby_array_pattern_child_type ref +); + +ruby_array_pattern_def( + unique int id: @ruby_array_pattern +); + +ruby_as_pattern_def( + unique int id: @ruby_as_pattern, + int name: @ruby_token_identifier ref, + int value: @ruby_underscore_pattern_expr ref +); + +@ruby_assignment_left_type = @ruby_left_assignment_list | @ruby_underscore_lhs + +@ruby_assignment_right_type = @ruby_right_assignment_list | @ruby_splat_argument | @ruby_underscore_expression + +ruby_assignment_def( + unique int id: @ruby_assignment, + int left: @ruby_assignment_left_type ref, + int right: @ruby_assignment_right_type ref +); + +@ruby_bare_string_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_bare_string, index] +ruby_bare_string_child( + int ruby_bare_string: @ruby_bare_string ref, + int index: int ref, + unique int child: @ruby_bare_string_child_type ref +); + +ruby_bare_string_def( + unique int id: @ruby_bare_string +); + +@ruby_bare_symbol_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_bare_symbol, index] +ruby_bare_symbol_child( + int ruby_bare_symbol: @ruby_bare_symbol ref, + int index: int ref, + unique int child: @ruby_bare_symbol_child_type ref +); + +ruby_bare_symbol_def( + unique int id: @ruby_bare_symbol +); + +@ruby_begin_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_begin, index] +ruby_begin_child( + int ruby_begin: @ruby_begin ref, + int index: int ref, + unique int child: @ruby_begin_child_type ref +); + +ruby_begin_def( + unique int id: @ruby_begin +); + +@ruby_begin_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_begin_block, index] +ruby_begin_block_child( + int ruby_begin_block: @ruby_begin_block ref, + int index: int ref, + unique int child: @ruby_begin_block_child_type ref +); + +ruby_begin_block_def( + unique int id: @ruby_begin_block +); + +case @ruby_binary.operator of + 0 = @ruby_binary_bangequal +| 1 = @ruby_binary_bangtilde +| 2 = @ruby_binary_percent +| 3 = @ruby_binary_ampersand +| 4 = @ruby_binary_ampersandampersand +| 5 = @ruby_binary_star +| 6 = @ruby_binary_starstar +| 7 = @ruby_binary_plus +| 8 = @ruby_binary_minus +| 9 = @ruby_binary_slash +| 10 = @ruby_binary_langle +| 11 = @ruby_binary_langlelangle +| 12 = @ruby_binary_langleequal +| 13 = @ruby_binary_langleequalrangle +| 14 = @ruby_binary_equalequal +| 15 = @ruby_binary_equalequalequal +| 16 = @ruby_binary_equaltilde +| 17 = @ruby_binary_rangle +| 18 = @ruby_binary_rangleequal +| 19 = @ruby_binary_ranglerangle +| 20 = @ruby_binary_caret +| 21 = @ruby_binary_and +| 22 = @ruby_binary_or +| 23 = @ruby_binary_pipe +| 24 = @ruby_binary_pipepipe +; + + +ruby_binary_def( + unique int id: @ruby_binary, + int left: @ruby_underscore_expression ref, + int operator: int ref, + int right: @ruby_underscore_expression ref +); + +ruby_block_parameters( + unique int ruby_block: @ruby_block ref, + unique int parameters: @ruby_block_parameters ref +); + +@ruby_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_block, index] +ruby_block_child( + int ruby_block: @ruby_block ref, + int index: int ref, + unique int child: @ruby_block_child_type ref +); + +ruby_block_def( + unique int id: @ruby_block +); + +ruby_block_argument_child( + unique int ruby_block_argument: @ruby_block_argument ref, + unique int child: @ruby_underscore_arg ref +); + +ruby_block_argument_def( + unique int id: @ruby_block_argument +); + +ruby_block_parameter_name( + unique int ruby_block_parameter: @ruby_block_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_block_parameter_def( + unique int id: @ruby_block_parameter +); + +@ruby_block_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_block_parameters, index] +ruby_block_parameters_child( + int ruby_block_parameters: @ruby_block_parameters ref, + int index: int ref, + unique int child: @ruby_block_parameters_child_type ref +); + +ruby_block_parameters_def( + unique int id: @ruby_block_parameters +); + +ruby_break_child( + unique int ruby_break: @ruby_break ref, + unique int child: @ruby_argument_list ref +); + +ruby_break_def( + unique int id: @ruby_break +); + +ruby_call_arguments( + unique int ruby_call: @ruby_call ref, + unique int arguments: @ruby_argument_list ref +); + +@ruby_call_block_type = @ruby_block | @ruby_do_block + +ruby_call_block( + unique int ruby_call: @ruby_call ref, + unique int block: @ruby_call_block_type ref +); + +@ruby_call_method_type = @ruby_argument_list | @ruby_scope_resolution | @ruby_token_operator | @ruby_underscore_variable + +@ruby_call_receiver_type = @ruby_call | @ruby_underscore_primary + +ruby_call_receiver( + unique int ruby_call: @ruby_call ref, + unique int receiver: @ruby_call_receiver_type ref +); + +ruby_call_def( + unique int id: @ruby_call, + int method: @ruby_call_method_type ref +); + +ruby_case_value( + unique int ruby_case__: @ruby_case__ ref, + unique int value: @ruby_underscore_statement ref +); + +@ruby_case_child_type = @ruby_else | @ruby_when + +#keyset[ruby_case__, index] +ruby_case_child( + int ruby_case__: @ruby_case__ ref, + int index: int ref, + unique int child: @ruby_case_child_type ref +); + +ruby_case_def( + unique int id: @ruby_case__ +); + +#keyset[ruby_case_match, index] +ruby_case_match_clauses( + int ruby_case_match: @ruby_case_match ref, + int index: int ref, + unique int clauses: @ruby_in_clause ref +); + +ruby_case_match_else( + unique int ruby_case_match: @ruby_case_match ref, + unique int else: @ruby_else ref +); + +ruby_case_match_def( + unique int id: @ruby_case_match, + int value: @ruby_underscore_statement ref +); + +#keyset[ruby_chained_string, index] +ruby_chained_string_child( + int ruby_chained_string: @ruby_chained_string ref, + int index: int ref, + unique int child: @ruby_string__ ref +); + +ruby_chained_string_def( + unique int id: @ruby_chained_string +); + +@ruby_class_name_type = @ruby_scope_resolution | @ruby_token_constant + +ruby_class_superclass( + unique int ruby_class: @ruby_class ref, + unique int superclass: @ruby_superclass ref +); + +@ruby_class_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_class, index] +ruby_class_child( + int ruby_class: @ruby_class ref, + int index: int ref, + unique int child: @ruby_class_child_type ref +); + +ruby_class_def( + unique int id: @ruby_class, + int name: @ruby_class_name_type ref +); + +ruby_conditional_def( + unique int id: @ruby_conditional, + int alternative: @ruby_underscore_arg ref, + int condition: @ruby_underscore_arg ref, + int consequence: @ruby_underscore_arg ref +); + +@ruby_delimited_symbol_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_delimited_symbol, index] +ruby_delimited_symbol_child( + int ruby_delimited_symbol: @ruby_delimited_symbol ref, + int index: int ref, + unique int child: @ruby_delimited_symbol_child_type ref +); + +ruby_delimited_symbol_def( + unique int id: @ruby_delimited_symbol +); + +@ruby_destructured_left_assignment_child_type = @ruby_destructured_left_assignment | @ruby_rest_assignment | @ruby_underscore_lhs + +#keyset[ruby_destructured_left_assignment, index] +ruby_destructured_left_assignment_child( + int ruby_destructured_left_assignment: @ruby_destructured_left_assignment ref, + int index: int ref, + unique int child: @ruby_destructured_left_assignment_child_type ref +); + +ruby_destructured_left_assignment_def( + unique int id: @ruby_destructured_left_assignment +); + +@ruby_destructured_parameter_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_destructured_parameter, index] +ruby_destructured_parameter_child( + int ruby_destructured_parameter: @ruby_destructured_parameter ref, + int index: int ref, + unique int child: @ruby_destructured_parameter_child_type ref +); + +ruby_destructured_parameter_def( + unique int id: @ruby_destructured_parameter +); + +@ruby_do_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_do, index] +ruby_do_child( + int ruby_do: @ruby_do ref, + int index: int ref, + unique int child: @ruby_do_child_type ref +); + +ruby_do_def( + unique int id: @ruby_do +); + +ruby_do_block_parameters( + unique int ruby_do_block: @ruby_do_block ref, + unique int parameters: @ruby_block_parameters ref +); + +@ruby_do_block_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_do_block, index] +ruby_do_block_child( + int ruby_do_block: @ruby_do_block ref, + int index: int ref, + unique int child: @ruby_do_block_child_type ref +); + +ruby_do_block_def( + unique int id: @ruby_do_block +); + +@ruby_element_reference_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_element_reference, index] +ruby_element_reference_child( + int ruby_element_reference: @ruby_element_reference ref, + int index: int ref, + unique int child: @ruby_element_reference_child_type ref +); + +ruby_element_reference_def( + unique int id: @ruby_element_reference, + int object: @ruby_underscore_primary ref +); + +@ruby_else_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_else, index] +ruby_else_child( + int ruby_else: @ruby_else ref, + int index: int ref, + unique int child: @ruby_else_child_type ref +); + +ruby_else_def( + unique int id: @ruby_else +); + +@ruby_elsif_alternative_type = @ruby_else | @ruby_elsif + +ruby_elsif_alternative( + unique int ruby_elsif: @ruby_elsif ref, + unique int alternative: @ruby_elsif_alternative_type ref +); + +ruby_elsif_consequence( + unique int ruby_elsif: @ruby_elsif ref, + unique int consequence: @ruby_then ref +); + +ruby_elsif_def( + unique int id: @ruby_elsif, + int condition: @ruby_underscore_statement ref +); + +@ruby_end_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_end_block, index] +ruby_end_block_child( + int ruby_end_block: @ruby_end_block ref, + int index: int ref, + unique int child: @ruby_end_block_child_type ref +); + +ruby_end_block_def( + unique int id: @ruby_end_block +); + +@ruby_ensure_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_ensure, index] +ruby_ensure_child( + int ruby_ensure: @ruby_ensure ref, + int index: int ref, + unique int child: @ruby_ensure_child_type ref +); + +ruby_ensure_def( + unique int id: @ruby_ensure +); + +ruby_exception_variable_def( + unique int id: @ruby_exception_variable, + int child: @ruby_underscore_lhs ref +); + +@ruby_exceptions_child_type = @ruby_splat_argument | @ruby_underscore_arg + +#keyset[ruby_exceptions, index] +ruby_exceptions_child( + int ruby_exceptions: @ruby_exceptions ref, + int index: int ref, + unique int child: @ruby_exceptions_child_type ref +); + +ruby_exceptions_def( + unique int id: @ruby_exceptions +); + +ruby_expression_reference_pattern_def( + unique int id: @ruby_expression_reference_pattern, + int value: @ruby_underscore_expression ref +); + +ruby_find_pattern_class( + unique int ruby_find_pattern: @ruby_find_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_find_pattern_child_type = @ruby_splat_parameter | @ruby_underscore_pattern_expr + +#keyset[ruby_find_pattern, index] +ruby_find_pattern_child( + int ruby_find_pattern: @ruby_find_pattern ref, + int index: int ref, + unique int child: @ruby_find_pattern_child_type ref +); + +ruby_find_pattern_def( + unique int id: @ruby_find_pattern +); + +@ruby_for_pattern_type = @ruby_left_assignment_list | @ruby_underscore_lhs + +ruby_for_def( + unique int id: @ruby_for, + int body: @ruby_do ref, + int pattern: @ruby_for_pattern_type ref, + int value: @ruby_in ref +); + +@ruby_hash_child_type = @ruby_hash_splat_argument | @ruby_pair + +#keyset[ruby_hash, index] +ruby_hash_child( + int ruby_hash: @ruby_hash ref, + int index: int ref, + unique int child: @ruby_hash_child_type ref +); + +ruby_hash_def( + unique int id: @ruby_hash +); + +ruby_hash_pattern_class( + unique int ruby_hash_pattern: @ruby_hash_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_hash_pattern_child_type = @ruby_hash_splat_parameter | @ruby_keyword_pattern | @ruby_token_hash_splat_nil + +#keyset[ruby_hash_pattern, index] +ruby_hash_pattern_child( + int ruby_hash_pattern: @ruby_hash_pattern ref, + int index: int ref, + unique int child: @ruby_hash_pattern_child_type ref +); + +ruby_hash_pattern_def( + unique int id: @ruby_hash_pattern +); + +ruby_hash_splat_argument_def( + unique int id: @ruby_hash_splat_argument, + int child: @ruby_underscore_arg ref +); + +ruby_hash_splat_parameter_name( + unique int ruby_hash_splat_parameter: @ruby_hash_splat_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_hash_splat_parameter_def( + unique int id: @ruby_hash_splat_parameter +); + +@ruby_heredoc_body_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_heredoc_content | @ruby_token_heredoc_end + +#keyset[ruby_heredoc_body, index] +ruby_heredoc_body_child( + int ruby_heredoc_body: @ruby_heredoc_body ref, + int index: int ref, + unique int child: @ruby_heredoc_body_child_type ref +); + +ruby_heredoc_body_def( + unique int id: @ruby_heredoc_body +); + +@ruby_if_alternative_type = @ruby_else | @ruby_elsif + +ruby_if_alternative( + unique int ruby_if: @ruby_if ref, + unique int alternative: @ruby_if_alternative_type ref +); + +ruby_if_consequence( + unique int ruby_if: @ruby_if ref, + unique int consequence: @ruby_then ref +); + +ruby_if_def( + unique int id: @ruby_if, + int condition: @ruby_underscore_statement ref +); + +ruby_if_guard_def( + unique int id: @ruby_if_guard, + int condition: @ruby_underscore_expression ref +); + +ruby_if_modifier_def( + unique int id: @ruby_if_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_in_def( + unique int id: @ruby_in, + int child: @ruby_underscore_arg ref +); + +ruby_in_clause_body( + unique int ruby_in_clause: @ruby_in_clause ref, + unique int body: @ruby_then ref +); + +@ruby_in_clause_guard_type = @ruby_if_guard | @ruby_unless_guard + +ruby_in_clause_guard( + unique int ruby_in_clause: @ruby_in_clause ref, + unique int guard: @ruby_in_clause_guard_type ref +); + +ruby_in_clause_def( + unique int id: @ruby_in_clause, + int pattern: @ruby_underscore_pattern_top_expr_body ref +); + +@ruby_interpolation_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_interpolation, index] +ruby_interpolation_child( + int ruby_interpolation: @ruby_interpolation ref, + int index: int ref, + unique int child: @ruby_interpolation_child_type ref +); + +ruby_interpolation_def( + unique int id: @ruby_interpolation +); + +ruby_keyword_parameter_value( + unique int ruby_keyword_parameter: @ruby_keyword_parameter ref, + unique int value: @ruby_underscore_arg ref +); + +ruby_keyword_parameter_def( + unique int id: @ruby_keyword_parameter, + int name: @ruby_token_identifier ref +); + +@ruby_keyword_pattern_key_type = @ruby_string__ | @ruby_token_hash_key_symbol + +ruby_keyword_pattern_value( + unique int ruby_keyword_pattern: @ruby_keyword_pattern ref, + unique int value: @ruby_underscore_pattern_expr ref +); + +ruby_keyword_pattern_def( + unique int id: @ruby_keyword_pattern, + int key__: @ruby_keyword_pattern_key_type ref +); + +@ruby_lambda_body_type = @ruby_block | @ruby_do_block + +ruby_lambda_parameters( + unique int ruby_lambda: @ruby_lambda ref, + unique int parameters: @ruby_lambda_parameters ref +); + +ruby_lambda_def( + unique int id: @ruby_lambda, + int body: @ruby_lambda_body_type ref +); + +@ruby_lambda_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_lambda_parameters, index] +ruby_lambda_parameters_child( + int ruby_lambda_parameters: @ruby_lambda_parameters ref, + int index: int ref, + unique int child: @ruby_lambda_parameters_child_type ref +); + +ruby_lambda_parameters_def( + unique int id: @ruby_lambda_parameters +); + +@ruby_left_assignment_list_child_type = @ruby_destructured_left_assignment | @ruby_rest_assignment | @ruby_underscore_lhs + +#keyset[ruby_left_assignment_list, index] +ruby_left_assignment_list_child( + int ruby_left_assignment_list: @ruby_left_assignment_list ref, + int index: int ref, + unique int child: @ruby_left_assignment_list_child_type ref +); + +ruby_left_assignment_list_def( + unique int id: @ruby_left_assignment_list +); + +ruby_method_parameters( + unique int ruby_method: @ruby_method ref, + unique int parameters: @ruby_method_parameters ref +); + +@ruby_method_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_arg | @ruby_underscore_statement + +#keyset[ruby_method, index] +ruby_method_child( + int ruby_method: @ruby_method ref, + int index: int ref, + unique int child: @ruby_method_child_type ref +); + +ruby_method_def( + unique int id: @ruby_method, + int name: @ruby_underscore_method_name ref +); + +@ruby_method_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_method_parameters, index] +ruby_method_parameters_child( + int ruby_method_parameters: @ruby_method_parameters ref, + int index: int ref, + unique int child: @ruby_method_parameters_child_type ref +); + +ruby_method_parameters_def( + unique int id: @ruby_method_parameters +); + +@ruby_module_name_type = @ruby_scope_resolution | @ruby_token_constant + +@ruby_module_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_module, index] +ruby_module_child( + int ruby_module: @ruby_module ref, + int index: int ref, + unique int child: @ruby_module_child_type ref +); + +ruby_module_def( + unique int id: @ruby_module, + int name: @ruby_module_name_type ref +); + +ruby_next_child( + unique int ruby_next: @ruby_next ref, + unique int child: @ruby_argument_list ref +); + +ruby_next_def( + unique int id: @ruby_next +); + +case @ruby_operator_assignment.operator of + 0 = @ruby_operator_assignment_percentequal +| 1 = @ruby_operator_assignment_ampersandampersandequal +| 2 = @ruby_operator_assignment_ampersandequal +| 3 = @ruby_operator_assignment_starstarequal +| 4 = @ruby_operator_assignment_starequal +| 5 = @ruby_operator_assignment_plusequal +| 6 = @ruby_operator_assignment_minusequal +| 7 = @ruby_operator_assignment_slashequal +| 8 = @ruby_operator_assignment_langlelangleequal +| 9 = @ruby_operator_assignment_ranglerangleequal +| 10 = @ruby_operator_assignment_caretequal +| 11 = @ruby_operator_assignment_pipeequal +| 12 = @ruby_operator_assignment_pipepipeequal +; + + +ruby_operator_assignment_def( + unique int id: @ruby_operator_assignment, + int left: @ruby_underscore_lhs ref, + int operator: int ref, + int right: @ruby_underscore_expression ref +); + +ruby_optional_parameter_def( + unique int id: @ruby_optional_parameter, + int name: @ruby_token_identifier ref, + int value: @ruby_underscore_arg ref +); + +@ruby_pair_key_type = @ruby_string__ | @ruby_token_hash_key_symbol | @ruby_underscore_arg + +ruby_pair_value( + unique int ruby_pair: @ruby_pair ref, + unique int value: @ruby_underscore_arg ref +); + +ruby_pair_def( + unique int id: @ruby_pair, + int key__: @ruby_pair_key_type ref +); + +ruby_parenthesized_pattern_def( + unique int id: @ruby_parenthesized_pattern, + int child: @ruby_underscore_pattern_expr ref +); + +@ruby_parenthesized_statements_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_parenthesized_statements, index] +ruby_parenthesized_statements_child( + int ruby_parenthesized_statements: @ruby_parenthesized_statements ref, + int index: int ref, + unique int child: @ruby_parenthesized_statements_child_type ref +); + +ruby_parenthesized_statements_def( + unique int id: @ruby_parenthesized_statements +); + +@ruby_pattern_child_type = @ruby_splat_argument | @ruby_underscore_arg + +ruby_pattern_def( + unique int id: @ruby_pattern, + int child: @ruby_pattern_child_type ref +); + +@ruby_program_child_type = @ruby_token_empty_statement | @ruby_token_uninterpreted | @ruby_underscore_statement + +#keyset[ruby_program, index] +ruby_program_child( + int ruby_program: @ruby_program ref, + int index: int ref, + unique int child: @ruby_program_child_type ref +); + +ruby_program_def( + unique int id: @ruby_program +); + +@ruby_range_begin_type = @ruby_underscore_arg | @ruby_underscore_pattern_primitive + +ruby_range_begin( + unique int ruby_range: @ruby_range ref, + unique int begin: @ruby_range_begin_type ref +); + +@ruby_range_end_type = @ruby_underscore_arg | @ruby_underscore_pattern_primitive + +ruby_range_end( + unique int ruby_range: @ruby_range ref, + unique int end: @ruby_range_end_type ref +); + +case @ruby_range.operator of + 0 = @ruby_range_dotdot +| 1 = @ruby_range_dotdotdot +; + + +ruby_range_def( + unique int id: @ruby_range, + int operator: int ref +); + +@ruby_rational_child_type = @ruby_token_float | @ruby_token_integer + +ruby_rational_def( + unique int id: @ruby_rational, + int child: @ruby_rational_child_type ref +); + +ruby_redo_child( + unique int ruby_redo: @ruby_redo ref, + unique int child: @ruby_argument_list ref +); + +ruby_redo_def( + unique int id: @ruby_redo +); + +@ruby_regex_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_regex, index] +ruby_regex_child( + int ruby_regex: @ruby_regex ref, + int index: int ref, + unique int child: @ruby_regex_child_type ref +); + +ruby_regex_def( + unique int id: @ruby_regex +); + +ruby_rescue_body( + unique int ruby_rescue: @ruby_rescue ref, + unique int body: @ruby_then ref +); + +ruby_rescue_exceptions( + unique int ruby_rescue: @ruby_rescue ref, + unique int exceptions: @ruby_exceptions ref +); + +ruby_rescue_variable( + unique int ruby_rescue: @ruby_rescue ref, + unique int variable: @ruby_exception_variable ref +); + +ruby_rescue_def( + unique int id: @ruby_rescue +); + +@ruby_rescue_modifier_body_type = @ruby_underscore_arg | @ruby_underscore_statement + +ruby_rescue_modifier_def( + unique int id: @ruby_rescue_modifier, + int body: @ruby_rescue_modifier_body_type ref, + int handler: @ruby_underscore_expression ref +); + +ruby_rest_assignment_child( + unique int ruby_rest_assignment: @ruby_rest_assignment ref, + unique int child: @ruby_underscore_lhs ref +); + +ruby_rest_assignment_def( + unique int id: @ruby_rest_assignment +); + +ruby_retry_child( + unique int ruby_retry: @ruby_retry ref, + unique int child: @ruby_argument_list ref +); + +ruby_retry_def( + unique int id: @ruby_retry +); + +ruby_return_child( + unique int ruby_return: @ruby_return ref, + unique int child: @ruby_argument_list ref +); + +ruby_return_def( + unique int id: @ruby_return +); + +@ruby_right_assignment_list_child_type = @ruby_splat_argument | @ruby_underscore_arg + +#keyset[ruby_right_assignment_list, index] +ruby_right_assignment_list_child( + int ruby_right_assignment_list: @ruby_right_assignment_list ref, + int index: int ref, + unique int child: @ruby_right_assignment_list_child_type ref +); + +ruby_right_assignment_list_def( + unique int id: @ruby_right_assignment_list +); + +@ruby_scope_resolution_name_type = @ruby_token_constant | @ruby_token_identifier + +@ruby_scope_resolution_scope_type = @ruby_underscore_pattern_constant | @ruby_underscore_primary + +ruby_scope_resolution_scope( + unique int ruby_scope_resolution: @ruby_scope_resolution ref, + unique int scope: @ruby_scope_resolution_scope_type ref +); + +ruby_scope_resolution_def( + unique int id: @ruby_scope_resolution, + int name: @ruby_scope_resolution_name_type ref +); + +ruby_setter_def( + unique int id: @ruby_setter, + int name: @ruby_token_identifier ref +); + +@ruby_singleton_class_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_singleton_class, index] +ruby_singleton_class_child( + int ruby_singleton_class: @ruby_singleton_class ref, + int index: int ref, + unique int child: @ruby_singleton_class_child_type ref +); + +ruby_singleton_class_def( + unique int id: @ruby_singleton_class, + int value: @ruby_underscore_arg ref +); + +@ruby_singleton_method_object_type = @ruby_underscore_arg | @ruby_underscore_variable + +ruby_singleton_method_parameters( + unique int ruby_singleton_method: @ruby_singleton_method ref, + unique int parameters: @ruby_method_parameters ref +); + +@ruby_singleton_method_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_arg | @ruby_underscore_statement + +#keyset[ruby_singleton_method, index] +ruby_singleton_method_child( + int ruby_singleton_method: @ruby_singleton_method ref, + int index: int ref, + unique int child: @ruby_singleton_method_child_type ref +); + +ruby_singleton_method_def( + unique int id: @ruby_singleton_method, + int name: @ruby_underscore_method_name ref, + int object: @ruby_singleton_method_object_type ref +); + +ruby_splat_argument_def( + unique int id: @ruby_splat_argument, + int child: @ruby_underscore_arg ref +); + +ruby_splat_parameter_name( + unique int ruby_splat_parameter: @ruby_splat_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_splat_parameter_def( + unique int id: @ruby_splat_parameter +); + +@ruby_string_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_string__, index] +ruby_string_child( + int ruby_string__: @ruby_string__ ref, + int index: int ref, + unique int child: @ruby_string_child_type ref +); + +ruby_string_def( + unique int id: @ruby_string__ +); + +#keyset[ruby_string_array, index] +ruby_string_array_child( + int ruby_string_array: @ruby_string_array ref, + int index: int ref, + unique int child: @ruby_bare_string ref +); + +ruby_string_array_def( + unique int id: @ruby_string_array +); + +@ruby_subshell_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_subshell, index] +ruby_subshell_child( + int ruby_subshell: @ruby_subshell ref, + int index: int ref, + unique int child: @ruby_subshell_child_type ref +); + +ruby_subshell_def( + unique int id: @ruby_subshell +); + +ruby_superclass_def( + unique int id: @ruby_superclass, + int child: @ruby_underscore_expression ref +); + +#keyset[ruby_symbol_array, index] +ruby_symbol_array_child( + int ruby_symbol_array: @ruby_symbol_array ref, + int index: int ref, + unique int child: @ruby_bare_symbol ref +); + +ruby_symbol_array_def( + unique int id: @ruby_symbol_array +); + +@ruby_then_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_then, index] +ruby_then_child( + int ruby_then: @ruby_then ref, + int index: int ref, + unique int child: @ruby_then_child_type ref +); + +ruby_then_def( + unique int id: @ruby_then +); + +@ruby_unary_operand_type = @ruby_parenthesized_statements | @ruby_underscore_expression | @ruby_underscore_simple_numeric + +case @ruby_unary.operator of + 0 = @ruby_unary_bang +| 1 = @ruby_unary_plus +| 2 = @ruby_unary_minus +| 3 = @ruby_unary_definedquestion +| 4 = @ruby_unary_not +| 5 = @ruby_unary_tilde +; + + +ruby_unary_def( + unique int id: @ruby_unary, + int operand: @ruby_unary_operand_type ref, + int operator: int ref +); + +#keyset[ruby_undef, index] +ruby_undef_child( + int ruby_undef: @ruby_undef ref, + int index: int ref, + unique int child: @ruby_underscore_method_name ref +); + +ruby_undef_def( + unique int id: @ruby_undef +); + +@ruby_unless_alternative_type = @ruby_else | @ruby_elsif + +ruby_unless_alternative( + unique int ruby_unless: @ruby_unless ref, + unique int alternative: @ruby_unless_alternative_type ref +); + +ruby_unless_consequence( + unique int ruby_unless: @ruby_unless ref, + unique int consequence: @ruby_then ref +); + +ruby_unless_def( + unique int id: @ruby_unless, + int condition: @ruby_underscore_statement ref +); + +ruby_unless_guard_def( + unique int id: @ruby_unless_guard, + int condition: @ruby_underscore_expression ref +); + +ruby_unless_modifier_def( + unique int id: @ruby_unless_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_until_def( + unique int id: @ruby_until, + int body: @ruby_do ref, + int condition: @ruby_underscore_statement ref +); + +ruby_until_modifier_def( + unique int id: @ruby_until_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +@ruby_variable_reference_pattern_name_type = @ruby_token_identifier | @ruby_underscore_nonlocal_variable + +ruby_variable_reference_pattern_def( + unique int id: @ruby_variable_reference_pattern, + int name: @ruby_variable_reference_pattern_name_type ref +); + +ruby_when_body( + unique int ruby_when: @ruby_when ref, + unique int body: @ruby_then ref +); + +#keyset[ruby_when, index] +ruby_when_pattern( + int ruby_when: @ruby_when ref, + int index: int ref, + unique int pattern: @ruby_pattern ref +); + +ruby_when_def( + unique int id: @ruby_when +); + +ruby_while_def( + unique int id: @ruby_while, + int body: @ruby_do ref, + int condition: @ruby_underscore_statement ref +); + +ruby_while_modifier_def( + unique int id: @ruby_while_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_yield_child( + unique int ruby_yield: @ruby_yield ref, + unique int child: @ruby_argument_list ref +); + +ruby_yield_def( + unique int id: @ruby_yield +); + +ruby_tokeninfo( + unique int id: @ruby_token, + int kind: int ref, + string value: string ref +); + +case @ruby_token.kind of + 0 = @ruby_reserved_word +| 1 = @ruby_token_character +| 2 = @ruby_token_class_variable +| 3 = @ruby_token_comment +| 4 = @ruby_token_complex +| 5 = @ruby_token_constant +| 6 = @ruby_token_empty_statement +| 7 = @ruby_token_encoding +| 8 = @ruby_token_escape_sequence +| 9 = @ruby_token_false +| 10 = @ruby_token_file +| 11 = @ruby_token_float +| 12 = @ruby_token_forward_argument +| 13 = @ruby_token_forward_parameter +| 14 = @ruby_token_global_variable +| 15 = @ruby_token_hash_key_symbol +| 16 = @ruby_token_hash_splat_nil +| 17 = @ruby_token_heredoc_beginning +| 18 = @ruby_token_heredoc_content +| 19 = @ruby_token_heredoc_end +| 20 = @ruby_token_identifier +| 21 = @ruby_token_instance_variable +| 22 = @ruby_token_integer +| 23 = @ruby_token_line +| 24 = @ruby_token_nil +| 25 = @ruby_token_operator +| 26 = @ruby_token_self +| 27 = @ruby_token_simple_symbol +| 28 = @ruby_token_string_content +| 29 = @ruby_token_super +| 30 = @ruby_token_true +| 31 = @ruby_token_uninterpreted +; + + +@ruby_ast_node = @ruby_alias | @ruby_alternative_pattern | @ruby_argument_list | @ruby_array | @ruby_array_pattern | @ruby_as_pattern | @ruby_assignment | @ruby_bare_string | @ruby_bare_symbol | @ruby_begin | @ruby_begin_block | @ruby_binary | @ruby_block | @ruby_block_argument | @ruby_block_parameter | @ruby_block_parameters | @ruby_break | @ruby_call | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_conditional | @ruby_delimited_symbol | @ruby_destructured_left_assignment | @ruby_destructured_parameter | @ruby_do | @ruby_do_block | @ruby_element_reference | @ruby_else | @ruby_elsif | @ruby_end_block | @ruby_ensure | @ruby_exception_variable | @ruby_exceptions | @ruby_expression_reference_pattern | @ruby_find_pattern | @ruby_for | @ruby_hash | @ruby_hash_pattern | @ruby_hash_splat_argument | @ruby_hash_splat_parameter | @ruby_heredoc_body | @ruby_if | @ruby_if_guard | @ruby_if_modifier | @ruby_in | @ruby_in_clause | @ruby_interpolation | @ruby_keyword_parameter | @ruby_keyword_pattern | @ruby_lambda | @ruby_lambda_parameters | @ruby_left_assignment_list | @ruby_method | @ruby_method_parameters | @ruby_module | @ruby_next | @ruby_operator_assignment | @ruby_optional_parameter | @ruby_pair | @ruby_parenthesized_pattern | @ruby_parenthesized_statements | @ruby_pattern | @ruby_program | @ruby_range | @ruby_rational | @ruby_redo | @ruby_regex | @ruby_rescue | @ruby_rescue_modifier | @ruby_rest_assignment | @ruby_retry | @ruby_return | @ruby_right_assignment_list | @ruby_scope_resolution | @ruby_setter | @ruby_singleton_class | @ruby_singleton_method | @ruby_splat_argument | @ruby_splat_parameter | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_superclass | @ruby_symbol_array | @ruby_then | @ruby_token | @ruby_unary | @ruby_undef | @ruby_unless | @ruby_unless_guard | @ruby_unless_modifier | @ruby_until | @ruby_until_modifier | @ruby_variable_reference_pattern | @ruby_when | @ruby_while | @ruby_while_modifier | @ruby_yield + +@ruby_ast_node_parent = @file | @ruby_ast_node + +#keyset[parent, parent_index] +ruby_ast_node_info( + unique int node: @ruby_ast_node ref, + int parent: @ruby_ast_node_parent ref, + int parent_index: int ref, + int loc: @location ref +); + +erb_comment_directive_def( + unique int id: @erb_comment_directive, + int child: @erb_token_comment ref +); + +erb_directive_def( + unique int id: @erb_directive, + int child: @erb_token_code ref +); + +erb_graphql_directive_def( + unique int id: @erb_graphql_directive, + int child: @erb_token_code ref +); + +erb_output_directive_def( + unique int id: @erb_output_directive, + int child: @erb_token_code ref +); + +@erb_template_child_type = @erb_comment_directive | @erb_directive | @erb_graphql_directive | @erb_output_directive | @erb_token_content + +#keyset[erb_template, index] +erb_template_child( + int erb_template: @erb_template ref, + int index: int ref, + unique int child: @erb_template_child_type ref +); + +erb_template_def( + unique int id: @erb_template +); + +erb_tokeninfo( + unique int id: @erb_token, + int kind: int ref, + string value: string ref +); + +case @erb_token.kind of + 0 = @erb_reserved_word +| 1 = @erb_token_code +| 2 = @erb_token_comment +| 3 = @erb_token_content +; + + +@erb_ast_node = @erb_comment_directive | @erb_directive | @erb_graphql_directive | @erb_output_directive | @erb_template | @erb_token + +@erb_ast_node_parent = @erb_ast_node | @file + +#keyset[parent, parent_index] +erb_ast_node_info( + unique int node: @erb_ast_node ref, + int parent: @erb_ast_node_parent ref, + int parent_index: int ref, + int loc: @location ref +); + diff --git a/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_block_parameters_child.ql b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_block_parameters_child.ql new file mode 100644 index 00000000000..7569c08cbfb --- /dev/null +++ b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_block_parameters_child.ql @@ -0,0 +1,14 @@ +class RubyBlockParameters extends @ruby_block_parameters { + string toString() { none() } +} + +class RubyBlockParameter extends @ruby_block_parameters_child_type { + string toString() { none() } +} + +from RubyBlockParameters ruby_block_parameters, int index, RubyBlockParameter param +where + ruby_block_parameters_child(ruby_block_parameters, index, param) or + ruby_block_parameters_locals(ruby_block_parameters, + index - 1 - max(int i | ruby_block_parameters_child(ruby_block_parameters, i, _)), param) +select ruby_block_parameters, index, param diff --git a/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_call_def.ql b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_call_def.ql new file mode 100644 index 00000000000..67a5994b6c8 --- /dev/null +++ b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_call_def.ql @@ -0,0 +1,14 @@ +class RubyAstNode extends @ruby_ast_node { + string toString() { none() } +} + +class RubyCall extends RubyAstNode, @ruby_call { } + +from RubyCall ruby_call, RubyAstNode method +where + ruby_call_method(ruby_call, method) + or + ruby_call_def(ruby_call) and + not ruby_call_method(ruby_call, _) and + ruby_call_arguments(ruby_call, method) +select ruby_call, method diff --git a/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_rational_def.ql b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_rational_def.ql new file mode 100644 index 00000000000..724a2388824 --- /dev/null +++ b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_rational_def.ql @@ -0,0 +1,7 @@ +private class RubyAstNode extends @ruby_ast_node { + string toString() { none() } +} + +from RubyAstNode node, RubyAstNode child +where ruby_rational_def(node, child) and not ruby_complex_def(_, node) +select node, child diff --git a/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_tokeninfo.ql b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_tokeninfo.ql new file mode 100644 index 00000000000..ce7c23c0e6c --- /dev/null +++ b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/ruby_tokeninfo.ql @@ -0,0 +1,37 @@ +private class RubyAstNode extends @ruby_ast_node { + string toString() { none() } +} + +bindingset[old] +private int newKind(int old) { + old <= 3 and result = old + or + old >= 4 and result = old + 1 +} + +private predicate complex_token(RubyAstNode node, string value) { + exists(RubyAstNode token, string tokenValue | ruby_tokeninfo(token, _, tokenValue) | + ( + ruby_complex_def(node, token) and value = tokenValue + "i" + or + exists(@ruby_rational rational | + ruby_complex_def(node, rational) and + ruby_rational_def(rational, token) + ) and + value = tokenValue + "ri" + ) + ) +} + +private RubyAstNode parent(RubyAstNode node) { ruby_ast_node_info(node, result, _, _) } + +from RubyAstNode token, int kind, string value +where + exists(int oldKind | + ruby_tokeninfo(token, oldKind, value) and + not complex_token(parent+(token), _) and + kind = newKind(oldKind) + ) + or + complex_token(token, value) and kind = 4 +select token, kind, value diff --git a/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/upgrade.properties b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/upgrade.properties new file mode 100644 index 00000000000..f1b4e1fd9f7 --- /dev/null +++ b/ruby/downgrades/1199e154f5e9b3560297633c6ebb4dfe0b191ae4/upgrade.properties @@ -0,0 +1,12 @@ +description: tree-sitter-ruby update +compatibility: backwards +ruby_tokeninfo.rel: run ruby_tokeninfo.qlo +ruby_block_parameters_child.rel: run ruby_block_parameters_child.qlo +ruby_call_def.rel: run ruby_call_def.qlo +ruby_rational_def.rel: run ruby_rational_def.qlo + + +ruby_call_method.rel: delete +ruby_complex_def.rel: delete +ruby_block_parameters_locals.rel: delete +ruby_call_operator: delete diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/old.dbscheme b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/old.dbscheme new file mode 100644 index 00000000000..9fdd1d40fd3 --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/old.dbscheme @@ -0,0 +1,1393 @@ +// CodeQL database schema for Ruby +// Automatically generated from the tree-sitter grammar; do not edit + +@location = @location_default + +locations_default( + unique int id: @location_default, + int file: @file ref, + int start_line: int ref, + int start_column: int ref, + int end_line: int ref, + int end_column: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @file | @folder + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +sourceLocationPrefix( + string prefix: string ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +case @diagnostic.severity of + 10 = @diagnostic_debug +| 20 = @diagnostic_info +| 30 = @diagnostic_warning +| 40 = @diagnostic_error +; + + +@ruby_underscore_arg = @ruby_assignment | @ruby_binary | @ruby_conditional | @ruby_operator_assignment | @ruby_range | @ruby_unary | @ruby_underscore_primary + +@ruby_underscore_expression = @ruby_assignment | @ruby_binary | @ruby_break | @ruby_call | @ruby_next | @ruby_operator_assignment | @ruby_return | @ruby_unary | @ruby_underscore_arg | @ruby_yield + +@ruby_underscore_lhs = @ruby_call | @ruby_element_reference | @ruby_scope_resolution | @ruby_token_false | @ruby_token_nil | @ruby_token_true | @ruby_underscore_variable + +@ruby_underscore_method_name = @ruby_delimited_symbol | @ruby_setter | @ruby_token_constant | @ruby_token_identifier | @ruby_token_operator | @ruby_token_simple_symbol | @ruby_underscore_nonlocal_variable + +@ruby_underscore_nonlocal_variable = @ruby_token_class_variable | @ruby_token_global_variable | @ruby_token_instance_variable + +@ruby_underscore_pattern_constant = @ruby_scope_resolution | @ruby_token_constant + +@ruby_underscore_pattern_expr = @ruby_alternative_pattern | @ruby_as_pattern | @ruby_underscore_pattern_expr_basic + +@ruby_underscore_pattern_expr_basic = @ruby_array_pattern | @ruby_expression_reference_pattern | @ruby_find_pattern | @ruby_hash_pattern | @ruby_parenthesized_pattern | @ruby_range | @ruby_token_identifier | @ruby_underscore_pattern_constant | @ruby_underscore_pattern_primitive | @ruby_variable_reference_pattern + +@ruby_underscore_pattern_primitive = @ruby_delimited_symbol | @ruby_lambda | @ruby_regex | @ruby_string__ | @ruby_string_array | @ruby_symbol_array | @ruby_token_encoding | @ruby_token_false | @ruby_token_file | @ruby_token_line | @ruby_token_nil | @ruby_token_self | @ruby_token_simple_symbol | @ruby_token_true | @ruby_unary | @ruby_underscore_simple_numeric + +@ruby_underscore_pattern_top_expr_body = @ruby_array_pattern | @ruby_find_pattern | @ruby_hash_pattern | @ruby_underscore_pattern_expr + +@ruby_underscore_primary = @ruby_array | @ruby_begin | @ruby_break | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_delimited_symbol | @ruby_for | @ruby_hash | @ruby_if | @ruby_lambda | @ruby_method | @ruby_module | @ruby_next | @ruby_parenthesized_statements | @ruby_redo | @ruby_regex | @ruby_retry | @ruby_return | @ruby_singleton_class | @ruby_singleton_method | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_symbol_array | @ruby_token_character | @ruby_token_heredoc_beginning | @ruby_token_simple_symbol | @ruby_unary | @ruby_underscore_lhs | @ruby_underscore_simple_numeric | @ruby_unless | @ruby_until | @ruby_while | @ruby_yield + +@ruby_underscore_simple_numeric = @ruby_rational | @ruby_token_complex | @ruby_token_float | @ruby_token_integer + +@ruby_underscore_statement = @ruby_alias | @ruby_begin_block | @ruby_end_block | @ruby_if_modifier | @ruby_rescue_modifier | @ruby_undef | @ruby_underscore_expression | @ruby_unless_modifier | @ruby_until_modifier | @ruby_while_modifier + +@ruby_underscore_variable = @ruby_token_constant | @ruby_token_identifier | @ruby_token_self | @ruby_token_super | @ruby_underscore_nonlocal_variable + +ruby_alias_def( + unique int id: @ruby_alias, + int alias: @ruby_underscore_method_name ref, + int name: @ruby_underscore_method_name ref +); + +#keyset[ruby_alternative_pattern, index] +ruby_alternative_pattern_alternatives( + int ruby_alternative_pattern: @ruby_alternative_pattern ref, + int index: int ref, + unique int alternatives: @ruby_underscore_pattern_expr_basic ref +); + +ruby_alternative_pattern_def( + unique int id: @ruby_alternative_pattern +); + +@ruby_argument_list_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_argument_list, index] +ruby_argument_list_child( + int ruby_argument_list: @ruby_argument_list ref, + int index: int ref, + unique int child: @ruby_argument_list_child_type ref +); + +ruby_argument_list_def( + unique int id: @ruby_argument_list +); + +@ruby_array_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_array, index] +ruby_array_child( + int ruby_array: @ruby_array ref, + int index: int ref, + unique int child: @ruby_array_child_type ref +); + +ruby_array_def( + unique int id: @ruby_array +); + +ruby_array_pattern_class( + unique int ruby_array_pattern: @ruby_array_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_array_pattern_child_type = @ruby_splat_parameter | @ruby_underscore_pattern_expr + +#keyset[ruby_array_pattern, index] +ruby_array_pattern_child( + int ruby_array_pattern: @ruby_array_pattern ref, + int index: int ref, + unique int child: @ruby_array_pattern_child_type ref +); + +ruby_array_pattern_def( + unique int id: @ruby_array_pattern +); + +ruby_as_pattern_def( + unique int id: @ruby_as_pattern, + int name: @ruby_token_identifier ref, + int value: @ruby_underscore_pattern_expr ref +); + +@ruby_assignment_left_type = @ruby_left_assignment_list | @ruby_underscore_lhs + +@ruby_assignment_right_type = @ruby_right_assignment_list | @ruby_splat_argument | @ruby_underscore_expression + +ruby_assignment_def( + unique int id: @ruby_assignment, + int left: @ruby_assignment_left_type ref, + int right: @ruby_assignment_right_type ref +); + +@ruby_bare_string_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_bare_string, index] +ruby_bare_string_child( + int ruby_bare_string: @ruby_bare_string ref, + int index: int ref, + unique int child: @ruby_bare_string_child_type ref +); + +ruby_bare_string_def( + unique int id: @ruby_bare_string +); + +@ruby_bare_symbol_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_bare_symbol, index] +ruby_bare_symbol_child( + int ruby_bare_symbol: @ruby_bare_symbol ref, + int index: int ref, + unique int child: @ruby_bare_symbol_child_type ref +); + +ruby_bare_symbol_def( + unique int id: @ruby_bare_symbol +); + +@ruby_begin_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_begin, index] +ruby_begin_child( + int ruby_begin: @ruby_begin ref, + int index: int ref, + unique int child: @ruby_begin_child_type ref +); + +ruby_begin_def( + unique int id: @ruby_begin +); + +@ruby_begin_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_begin_block, index] +ruby_begin_block_child( + int ruby_begin_block: @ruby_begin_block ref, + int index: int ref, + unique int child: @ruby_begin_block_child_type ref +); + +ruby_begin_block_def( + unique int id: @ruby_begin_block +); + +case @ruby_binary.operator of + 0 = @ruby_binary_bangequal +| 1 = @ruby_binary_bangtilde +| 2 = @ruby_binary_percent +| 3 = @ruby_binary_ampersand +| 4 = @ruby_binary_ampersandampersand +| 5 = @ruby_binary_star +| 6 = @ruby_binary_starstar +| 7 = @ruby_binary_plus +| 8 = @ruby_binary_minus +| 9 = @ruby_binary_slash +| 10 = @ruby_binary_langle +| 11 = @ruby_binary_langlelangle +| 12 = @ruby_binary_langleequal +| 13 = @ruby_binary_langleequalrangle +| 14 = @ruby_binary_equalequal +| 15 = @ruby_binary_equalequalequal +| 16 = @ruby_binary_equaltilde +| 17 = @ruby_binary_rangle +| 18 = @ruby_binary_rangleequal +| 19 = @ruby_binary_ranglerangle +| 20 = @ruby_binary_caret +| 21 = @ruby_binary_and +| 22 = @ruby_binary_or +| 23 = @ruby_binary_pipe +| 24 = @ruby_binary_pipepipe +; + + +ruby_binary_def( + unique int id: @ruby_binary, + int left: @ruby_underscore_expression ref, + int operator: int ref, + int right: @ruby_underscore_expression ref +); + +ruby_block_parameters( + unique int ruby_block: @ruby_block ref, + unique int parameters: @ruby_block_parameters ref +); + +@ruby_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_block, index] +ruby_block_child( + int ruby_block: @ruby_block ref, + int index: int ref, + unique int child: @ruby_block_child_type ref +); + +ruby_block_def( + unique int id: @ruby_block +); + +ruby_block_argument_child( + unique int ruby_block_argument: @ruby_block_argument ref, + unique int child: @ruby_underscore_arg ref +); + +ruby_block_argument_def( + unique int id: @ruby_block_argument +); + +ruby_block_parameter_name( + unique int ruby_block_parameter: @ruby_block_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_block_parameter_def( + unique int id: @ruby_block_parameter +); + +@ruby_block_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_block_parameters, index] +ruby_block_parameters_child( + int ruby_block_parameters: @ruby_block_parameters ref, + int index: int ref, + unique int child: @ruby_block_parameters_child_type ref +); + +ruby_block_parameters_def( + unique int id: @ruby_block_parameters +); + +ruby_break_child( + unique int ruby_break: @ruby_break ref, + unique int child: @ruby_argument_list ref +); + +ruby_break_def( + unique int id: @ruby_break +); + +ruby_call_arguments( + unique int ruby_call: @ruby_call ref, + unique int arguments: @ruby_argument_list ref +); + +@ruby_call_block_type = @ruby_block | @ruby_do_block + +ruby_call_block( + unique int ruby_call: @ruby_call ref, + unique int block: @ruby_call_block_type ref +); + +@ruby_call_method_type = @ruby_argument_list | @ruby_scope_resolution | @ruby_token_operator | @ruby_underscore_variable + +@ruby_call_receiver_type = @ruby_call | @ruby_underscore_primary + +ruby_call_receiver( + unique int ruby_call: @ruby_call ref, + unique int receiver: @ruby_call_receiver_type ref +); + +ruby_call_def( + unique int id: @ruby_call, + int method: @ruby_call_method_type ref +); + +ruby_case_value( + unique int ruby_case__: @ruby_case__ ref, + unique int value: @ruby_underscore_statement ref +); + +@ruby_case_child_type = @ruby_else | @ruby_when + +#keyset[ruby_case__, index] +ruby_case_child( + int ruby_case__: @ruby_case__ ref, + int index: int ref, + unique int child: @ruby_case_child_type ref +); + +ruby_case_def( + unique int id: @ruby_case__ +); + +#keyset[ruby_case_match, index] +ruby_case_match_clauses( + int ruby_case_match: @ruby_case_match ref, + int index: int ref, + unique int clauses: @ruby_in_clause ref +); + +ruby_case_match_else( + unique int ruby_case_match: @ruby_case_match ref, + unique int else: @ruby_else ref +); + +ruby_case_match_def( + unique int id: @ruby_case_match, + int value: @ruby_underscore_statement ref +); + +#keyset[ruby_chained_string, index] +ruby_chained_string_child( + int ruby_chained_string: @ruby_chained_string ref, + int index: int ref, + unique int child: @ruby_string__ ref +); + +ruby_chained_string_def( + unique int id: @ruby_chained_string +); + +@ruby_class_name_type = @ruby_scope_resolution | @ruby_token_constant + +ruby_class_superclass( + unique int ruby_class: @ruby_class ref, + unique int superclass: @ruby_superclass ref +); + +@ruby_class_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_class, index] +ruby_class_child( + int ruby_class: @ruby_class ref, + int index: int ref, + unique int child: @ruby_class_child_type ref +); + +ruby_class_def( + unique int id: @ruby_class, + int name: @ruby_class_name_type ref +); + +ruby_conditional_def( + unique int id: @ruby_conditional, + int alternative: @ruby_underscore_arg ref, + int condition: @ruby_underscore_arg ref, + int consequence: @ruby_underscore_arg ref +); + +@ruby_delimited_symbol_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_delimited_symbol, index] +ruby_delimited_symbol_child( + int ruby_delimited_symbol: @ruby_delimited_symbol ref, + int index: int ref, + unique int child: @ruby_delimited_symbol_child_type ref +); + +ruby_delimited_symbol_def( + unique int id: @ruby_delimited_symbol +); + +@ruby_destructured_left_assignment_child_type = @ruby_destructured_left_assignment | @ruby_rest_assignment | @ruby_underscore_lhs + +#keyset[ruby_destructured_left_assignment, index] +ruby_destructured_left_assignment_child( + int ruby_destructured_left_assignment: @ruby_destructured_left_assignment ref, + int index: int ref, + unique int child: @ruby_destructured_left_assignment_child_type ref +); + +ruby_destructured_left_assignment_def( + unique int id: @ruby_destructured_left_assignment +); + +@ruby_destructured_parameter_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_destructured_parameter, index] +ruby_destructured_parameter_child( + int ruby_destructured_parameter: @ruby_destructured_parameter ref, + int index: int ref, + unique int child: @ruby_destructured_parameter_child_type ref +); + +ruby_destructured_parameter_def( + unique int id: @ruby_destructured_parameter +); + +@ruby_do_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_do, index] +ruby_do_child( + int ruby_do: @ruby_do ref, + int index: int ref, + unique int child: @ruby_do_child_type ref +); + +ruby_do_def( + unique int id: @ruby_do +); + +ruby_do_block_parameters( + unique int ruby_do_block: @ruby_do_block ref, + unique int parameters: @ruby_block_parameters ref +); + +@ruby_do_block_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_do_block, index] +ruby_do_block_child( + int ruby_do_block: @ruby_do_block ref, + int index: int ref, + unique int child: @ruby_do_block_child_type ref +); + +ruby_do_block_def( + unique int id: @ruby_do_block +); + +@ruby_element_reference_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_element_reference, index] +ruby_element_reference_child( + int ruby_element_reference: @ruby_element_reference ref, + int index: int ref, + unique int child: @ruby_element_reference_child_type ref +); + +ruby_element_reference_def( + unique int id: @ruby_element_reference, + int object: @ruby_underscore_primary ref +); + +@ruby_else_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_else, index] +ruby_else_child( + int ruby_else: @ruby_else ref, + int index: int ref, + unique int child: @ruby_else_child_type ref +); + +ruby_else_def( + unique int id: @ruby_else +); + +@ruby_elsif_alternative_type = @ruby_else | @ruby_elsif + +ruby_elsif_alternative( + unique int ruby_elsif: @ruby_elsif ref, + unique int alternative: @ruby_elsif_alternative_type ref +); + +ruby_elsif_consequence( + unique int ruby_elsif: @ruby_elsif ref, + unique int consequence: @ruby_then ref +); + +ruby_elsif_def( + unique int id: @ruby_elsif, + int condition: @ruby_underscore_statement ref +); + +@ruby_end_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_end_block, index] +ruby_end_block_child( + int ruby_end_block: @ruby_end_block ref, + int index: int ref, + unique int child: @ruby_end_block_child_type ref +); + +ruby_end_block_def( + unique int id: @ruby_end_block +); + +@ruby_ensure_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_ensure, index] +ruby_ensure_child( + int ruby_ensure: @ruby_ensure ref, + int index: int ref, + unique int child: @ruby_ensure_child_type ref +); + +ruby_ensure_def( + unique int id: @ruby_ensure +); + +ruby_exception_variable_def( + unique int id: @ruby_exception_variable, + int child: @ruby_underscore_lhs ref +); + +@ruby_exceptions_child_type = @ruby_splat_argument | @ruby_underscore_arg + +#keyset[ruby_exceptions, index] +ruby_exceptions_child( + int ruby_exceptions: @ruby_exceptions ref, + int index: int ref, + unique int child: @ruby_exceptions_child_type ref +); + +ruby_exceptions_def( + unique int id: @ruby_exceptions +); + +ruby_expression_reference_pattern_def( + unique int id: @ruby_expression_reference_pattern, + int value: @ruby_underscore_expression ref +); + +ruby_find_pattern_class( + unique int ruby_find_pattern: @ruby_find_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_find_pattern_child_type = @ruby_splat_parameter | @ruby_underscore_pattern_expr + +#keyset[ruby_find_pattern, index] +ruby_find_pattern_child( + int ruby_find_pattern: @ruby_find_pattern ref, + int index: int ref, + unique int child: @ruby_find_pattern_child_type ref +); + +ruby_find_pattern_def( + unique int id: @ruby_find_pattern +); + +@ruby_for_pattern_type = @ruby_left_assignment_list | @ruby_underscore_lhs + +ruby_for_def( + unique int id: @ruby_for, + int body: @ruby_do ref, + int pattern: @ruby_for_pattern_type ref, + int value: @ruby_in ref +); + +@ruby_hash_child_type = @ruby_hash_splat_argument | @ruby_pair + +#keyset[ruby_hash, index] +ruby_hash_child( + int ruby_hash: @ruby_hash ref, + int index: int ref, + unique int child: @ruby_hash_child_type ref +); + +ruby_hash_def( + unique int id: @ruby_hash +); + +ruby_hash_pattern_class( + unique int ruby_hash_pattern: @ruby_hash_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_hash_pattern_child_type = @ruby_hash_splat_parameter | @ruby_keyword_pattern | @ruby_token_hash_splat_nil + +#keyset[ruby_hash_pattern, index] +ruby_hash_pattern_child( + int ruby_hash_pattern: @ruby_hash_pattern ref, + int index: int ref, + unique int child: @ruby_hash_pattern_child_type ref +); + +ruby_hash_pattern_def( + unique int id: @ruby_hash_pattern +); + +ruby_hash_splat_argument_def( + unique int id: @ruby_hash_splat_argument, + int child: @ruby_underscore_arg ref +); + +ruby_hash_splat_parameter_name( + unique int ruby_hash_splat_parameter: @ruby_hash_splat_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_hash_splat_parameter_def( + unique int id: @ruby_hash_splat_parameter +); + +@ruby_heredoc_body_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_heredoc_content | @ruby_token_heredoc_end + +#keyset[ruby_heredoc_body, index] +ruby_heredoc_body_child( + int ruby_heredoc_body: @ruby_heredoc_body ref, + int index: int ref, + unique int child: @ruby_heredoc_body_child_type ref +); + +ruby_heredoc_body_def( + unique int id: @ruby_heredoc_body +); + +@ruby_if_alternative_type = @ruby_else | @ruby_elsif + +ruby_if_alternative( + unique int ruby_if: @ruby_if ref, + unique int alternative: @ruby_if_alternative_type ref +); + +ruby_if_consequence( + unique int ruby_if: @ruby_if ref, + unique int consequence: @ruby_then ref +); + +ruby_if_def( + unique int id: @ruby_if, + int condition: @ruby_underscore_statement ref +); + +ruby_if_guard_def( + unique int id: @ruby_if_guard, + int condition: @ruby_underscore_expression ref +); + +ruby_if_modifier_def( + unique int id: @ruby_if_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_in_def( + unique int id: @ruby_in, + int child: @ruby_underscore_arg ref +); + +ruby_in_clause_body( + unique int ruby_in_clause: @ruby_in_clause ref, + unique int body: @ruby_then ref +); + +@ruby_in_clause_guard_type = @ruby_if_guard | @ruby_unless_guard + +ruby_in_clause_guard( + unique int ruby_in_clause: @ruby_in_clause ref, + unique int guard: @ruby_in_clause_guard_type ref +); + +ruby_in_clause_def( + unique int id: @ruby_in_clause, + int pattern: @ruby_underscore_pattern_top_expr_body ref +); + +@ruby_interpolation_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_interpolation, index] +ruby_interpolation_child( + int ruby_interpolation: @ruby_interpolation ref, + int index: int ref, + unique int child: @ruby_interpolation_child_type ref +); + +ruby_interpolation_def( + unique int id: @ruby_interpolation +); + +ruby_keyword_parameter_value( + unique int ruby_keyword_parameter: @ruby_keyword_parameter ref, + unique int value: @ruby_underscore_arg ref +); + +ruby_keyword_parameter_def( + unique int id: @ruby_keyword_parameter, + int name: @ruby_token_identifier ref +); + +@ruby_keyword_pattern_key_type = @ruby_string__ | @ruby_token_hash_key_symbol + +ruby_keyword_pattern_value( + unique int ruby_keyword_pattern: @ruby_keyword_pattern ref, + unique int value: @ruby_underscore_pattern_expr ref +); + +ruby_keyword_pattern_def( + unique int id: @ruby_keyword_pattern, + int key__: @ruby_keyword_pattern_key_type ref +); + +@ruby_lambda_body_type = @ruby_block | @ruby_do_block + +ruby_lambda_parameters( + unique int ruby_lambda: @ruby_lambda ref, + unique int parameters: @ruby_lambda_parameters ref +); + +ruby_lambda_def( + unique int id: @ruby_lambda, + int body: @ruby_lambda_body_type ref +); + +@ruby_lambda_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_lambda_parameters, index] +ruby_lambda_parameters_child( + int ruby_lambda_parameters: @ruby_lambda_parameters ref, + int index: int ref, + unique int child: @ruby_lambda_parameters_child_type ref +); + +ruby_lambda_parameters_def( + unique int id: @ruby_lambda_parameters +); + +@ruby_left_assignment_list_child_type = @ruby_destructured_left_assignment | @ruby_rest_assignment | @ruby_underscore_lhs + +#keyset[ruby_left_assignment_list, index] +ruby_left_assignment_list_child( + int ruby_left_assignment_list: @ruby_left_assignment_list ref, + int index: int ref, + unique int child: @ruby_left_assignment_list_child_type ref +); + +ruby_left_assignment_list_def( + unique int id: @ruby_left_assignment_list +); + +ruby_method_parameters( + unique int ruby_method: @ruby_method ref, + unique int parameters: @ruby_method_parameters ref +); + +@ruby_method_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_arg | @ruby_underscore_statement + +#keyset[ruby_method, index] +ruby_method_child( + int ruby_method: @ruby_method ref, + int index: int ref, + unique int child: @ruby_method_child_type ref +); + +ruby_method_def( + unique int id: @ruby_method, + int name: @ruby_underscore_method_name ref +); + +@ruby_method_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_method_parameters, index] +ruby_method_parameters_child( + int ruby_method_parameters: @ruby_method_parameters ref, + int index: int ref, + unique int child: @ruby_method_parameters_child_type ref +); + +ruby_method_parameters_def( + unique int id: @ruby_method_parameters +); + +@ruby_module_name_type = @ruby_scope_resolution | @ruby_token_constant + +@ruby_module_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_module, index] +ruby_module_child( + int ruby_module: @ruby_module ref, + int index: int ref, + unique int child: @ruby_module_child_type ref +); + +ruby_module_def( + unique int id: @ruby_module, + int name: @ruby_module_name_type ref +); + +ruby_next_child( + unique int ruby_next: @ruby_next ref, + unique int child: @ruby_argument_list ref +); + +ruby_next_def( + unique int id: @ruby_next +); + +case @ruby_operator_assignment.operator of + 0 = @ruby_operator_assignment_percentequal +| 1 = @ruby_operator_assignment_ampersandampersandequal +| 2 = @ruby_operator_assignment_ampersandequal +| 3 = @ruby_operator_assignment_starstarequal +| 4 = @ruby_operator_assignment_starequal +| 5 = @ruby_operator_assignment_plusequal +| 6 = @ruby_operator_assignment_minusequal +| 7 = @ruby_operator_assignment_slashequal +| 8 = @ruby_operator_assignment_langlelangleequal +| 9 = @ruby_operator_assignment_ranglerangleequal +| 10 = @ruby_operator_assignment_caretequal +| 11 = @ruby_operator_assignment_pipeequal +| 12 = @ruby_operator_assignment_pipepipeequal +; + + +ruby_operator_assignment_def( + unique int id: @ruby_operator_assignment, + int left: @ruby_underscore_lhs ref, + int operator: int ref, + int right: @ruby_underscore_expression ref +); + +ruby_optional_parameter_def( + unique int id: @ruby_optional_parameter, + int name: @ruby_token_identifier ref, + int value: @ruby_underscore_arg ref +); + +@ruby_pair_key_type = @ruby_string__ | @ruby_token_hash_key_symbol | @ruby_underscore_arg + +ruby_pair_value( + unique int ruby_pair: @ruby_pair ref, + unique int value: @ruby_underscore_arg ref +); + +ruby_pair_def( + unique int id: @ruby_pair, + int key__: @ruby_pair_key_type ref +); + +ruby_parenthesized_pattern_def( + unique int id: @ruby_parenthesized_pattern, + int child: @ruby_underscore_pattern_expr ref +); + +@ruby_parenthesized_statements_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_parenthesized_statements, index] +ruby_parenthesized_statements_child( + int ruby_parenthesized_statements: @ruby_parenthesized_statements ref, + int index: int ref, + unique int child: @ruby_parenthesized_statements_child_type ref +); + +ruby_parenthesized_statements_def( + unique int id: @ruby_parenthesized_statements +); + +@ruby_pattern_child_type = @ruby_splat_argument | @ruby_underscore_arg + +ruby_pattern_def( + unique int id: @ruby_pattern, + int child: @ruby_pattern_child_type ref +); + +@ruby_program_child_type = @ruby_token_empty_statement | @ruby_token_uninterpreted | @ruby_underscore_statement + +#keyset[ruby_program, index] +ruby_program_child( + int ruby_program: @ruby_program ref, + int index: int ref, + unique int child: @ruby_program_child_type ref +); + +ruby_program_def( + unique int id: @ruby_program +); + +@ruby_range_begin_type = @ruby_underscore_arg | @ruby_underscore_pattern_primitive + +ruby_range_begin( + unique int ruby_range: @ruby_range ref, + unique int begin: @ruby_range_begin_type ref +); + +@ruby_range_end_type = @ruby_underscore_arg | @ruby_underscore_pattern_primitive + +ruby_range_end( + unique int ruby_range: @ruby_range ref, + unique int end: @ruby_range_end_type ref +); + +case @ruby_range.operator of + 0 = @ruby_range_dotdot +| 1 = @ruby_range_dotdotdot +; + + +ruby_range_def( + unique int id: @ruby_range, + int operator: int ref +); + +@ruby_rational_child_type = @ruby_token_float | @ruby_token_integer + +ruby_rational_def( + unique int id: @ruby_rational, + int child: @ruby_rational_child_type ref +); + +ruby_redo_child( + unique int ruby_redo: @ruby_redo ref, + unique int child: @ruby_argument_list ref +); + +ruby_redo_def( + unique int id: @ruby_redo +); + +@ruby_regex_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_regex, index] +ruby_regex_child( + int ruby_regex: @ruby_regex ref, + int index: int ref, + unique int child: @ruby_regex_child_type ref +); + +ruby_regex_def( + unique int id: @ruby_regex +); + +ruby_rescue_body( + unique int ruby_rescue: @ruby_rescue ref, + unique int body: @ruby_then ref +); + +ruby_rescue_exceptions( + unique int ruby_rescue: @ruby_rescue ref, + unique int exceptions: @ruby_exceptions ref +); + +ruby_rescue_variable( + unique int ruby_rescue: @ruby_rescue ref, + unique int variable: @ruby_exception_variable ref +); + +ruby_rescue_def( + unique int id: @ruby_rescue +); + +@ruby_rescue_modifier_body_type = @ruby_underscore_arg | @ruby_underscore_statement + +ruby_rescue_modifier_def( + unique int id: @ruby_rescue_modifier, + int body: @ruby_rescue_modifier_body_type ref, + int handler: @ruby_underscore_expression ref +); + +ruby_rest_assignment_child( + unique int ruby_rest_assignment: @ruby_rest_assignment ref, + unique int child: @ruby_underscore_lhs ref +); + +ruby_rest_assignment_def( + unique int id: @ruby_rest_assignment +); + +ruby_retry_child( + unique int ruby_retry: @ruby_retry ref, + unique int child: @ruby_argument_list ref +); + +ruby_retry_def( + unique int id: @ruby_retry +); + +ruby_return_child( + unique int ruby_return: @ruby_return ref, + unique int child: @ruby_argument_list ref +); + +ruby_return_def( + unique int id: @ruby_return +); + +@ruby_right_assignment_list_child_type = @ruby_splat_argument | @ruby_underscore_arg + +#keyset[ruby_right_assignment_list, index] +ruby_right_assignment_list_child( + int ruby_right_assignment_list: @ruby_right_assignment_list ref, + int index: int ref, + unique int child: @ruby_right_assignment_list_child_type ref +); + +ruby_right_assignment_list_def( + unique int id: @ruby_right_assignment_list +); + +@ruby_scope_resolution_name_type = @ruby_token_constant | @ruby_token_identifier + +@ruby_scope_resolution_scope_type = @ruby_underscore_pattern_constant | @ruby_underscore_primary + +ruby_scope_resolution_scope( + unique int ruby_scope_resolution: @ruby_scope_resolution ref, + unique int scope: @ruby_scope_resolution_scope_type ref +); + +ruby_scope_resolution_def( + unique int id: @ruby_scope_resolution, + int name: @ruby_scope_resolution_name_type ref +); + +ruby_setter_def( + unique int id: @ruby_setter, + int name: @ruby_token_identifier ref +); + +@ruby_singleton_class_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_singleton_class, index] +ruby_singleton_class_child( + int ruby_singleton_class: @ruby_singleton_class ref, + int index: int ref, + unique int child: @ruby_singleton_class_child_type ref +); + +ruby_singleton_class_def( + unique int id: @ruby_singleton_class, + int value: @ruby_underscore_arg ref +); + +@ruby_singleton_method_object_type = @ruby_underscore_arg | @ruby_underscore_variable + +ruby_singleton_method_parameters( + unique int ruby_singleton_method: @ruby_singleton_method ref, + unique int parameters: @ruby_method_parameters ref +); + +@ruby_singleton_method_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_arg | @ruby_underscore_statement + +#keyset[ruby_singleton_method, index] +ruby_singleton_method_child( + int ruby_singleton_method: @ruby_singleton_method ref, + int index: int ref, + unique int child: @ruby_singleton_method_child_type ref +); + +ruby_singleton_method_def( + unique int id: @ruby_singleton_method, + int name: @ruby_underscore_method_name ref, + int object: @ruby_singleton_method_object_type ref +); + +ruby_splat_argument_def( + unique int id: @ruby_splat_argument, + int child: @ruby_underscore_arg ref +); + +ruby_splat_parameter_name( + unique int ruby_splat_parameter: @ruby_splat_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_splat_parameter_def( + unique int id: @ruby_splat_parameter +); + +@ruby_string_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_string__, index] +ruby_string_child( + int ruby_string__: @ruby_string__ ref, + int index: int ref, + unique int child: @ruby_string_child_type ref +); + +ruby_string_def( + unique int id: @ruby_string__ +); + +#keyset[ruby_string_array, index] +ruby_string_array_child( + int ruby_string_array: @ruby_string_array ref, + int index: int ref, + unique int child: @ruby_bare_string ref +); + +ruby_string_array_def( + unique int id: @ruby_string_array +); + +@ruby_subshell_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_subshell, index] +ruby_subshell_child( + int ruby_subshell: @ruby_subshell ref, + int index: int ref, + unique int child: @ruby_subshell_child_type ref +); + +ruby_subshell_def( + unique int id: @ruby_subshell +); + +ruby_superclass_def( + unique int id: @ruby_superclass, + int child: @ruby_underscore_expression ref +); + +#keyset[ruby_symbol_array, index] +ruby_symbol_array_child( + int ruby_symbol_array: @ruby_symbol_array ref, + int index: int ref, + unique int child: @ruby_bare_symbol ref +); + +ruby_symbol_array_def( + unique int id: @ruby_symbol_array +); + +@ruby_then_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_then, index] +ruby_then_child( + int ruby_then: @ruby_then ref, + int index: int ref, + unique int child: @ruby_then_child_type ref +); + +ruby_then_def( + unique int id: @ruby_then +); + +@ruby_unary_operand_type = @ruby_parenthesized_statements | @ruby_underscore_expression | @ruby_underscore_simple_numeric + +case @ruby_unary.operator of + 0 = @ruby_unary_bang +| 1 = @ruby_unary_plus +| 2 = @ruby_unary_minus +| 3 = @ruby_unary_definedquestion +| 4 = @ruby_unary_not +| 5 = @ruby_unary_tilde +; + + +ruby_unary_def( + unique int id: @ruby_unary, + int operand: @ruby_unary_operand_type ref, + int operator: int ref +); + +#keyset[ruby_undef, index] +ruby_undef_child( + int ruby_undef: @ruby_undef ref, + int index: int ref, + unique int child: @ruby_underscore_method_name ref +); + +ruby_undef_def( + unique int id: @ruby_undef +); + +@ruby_unless_alternative_type = @ruby_else | @ruby_elsif + +ruby_unless_alternative( + unique int ruby_unless: @ruby_unless ref, + unique int alternative: @ruby_unless_alternative_type ref +); + +ruby_unless_consequence( + unique int ruby_unless: @ruby_unless ref, + unique int consequence: @ruby_then ref +); + +ruby_unless_def( + unique int id: @ruby_unless, + int condition: @ruby_underscore_statement ref +); + +ruby_unless_guard_def( + unique int id: @ruby_unless_guard, + int condition: @ruby_underscore_expression ref +); + +ruby_unless_modifier_def( + unique int id: @ruby_unless_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_until_def( + unique int id: @ruby_until, + int body: @ruby_do ref, + int condition: @ruby_underscore_statement ref +); + +ruby_until_modifier_def( + unique int id: @ruby_until_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +@ruby_variable_reference_pattern_name_type = @ruby_token_identifier | @ruby_underscore_nonlocal_variable + +ruby_variable_reference_pattern_def( + unique int id: @ruby_variable_reference_pattern, + int name: @ruby_variable_reference_pattern_name_type ref +); + +ruby_when_body( + unique int ruby_when: @ruby_when ref, + unique int body: @ruby_then ref +); + +#keyset[ruby_when, index] +ruby_when_pattern( + int ruby_when: @ruby_when ref, + int index: int ref, + unique int pattern: @ruby_pattern ref +); + +ruby_when_def( + unique int id: @ruby_when +); + +ruby_while_def( + unique int id: @ruby_while, + int body: @ruby_do ref, + int condition: @ruby_underscore_statement ref +); + +ruby_while_modifier_def( + unique int id: @ruby_while_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_yield_child( + unique int ruby_yield: @ruby_yield ref, + unique int child: @ruby_argument_list ref +); + +ruby_yield_def( + unique int id: @ruby_yield +); + +ruby_tokeninfo( + unique int id: @ruby_token, + int kind: int ref, + string value: string ref +); + +case @ruby_token.kind of + 0 = @ruby_reserved_word +| 1 = @ruby_token_character +| 2 = @ruby_token_class_variable +| 3 = @ruby_token_comment +| 4 = @ruby_token_complex +| 5 = @ruby_token_constant +| 6 = @ruby_token_empty_statement +| 7 = @ruby_token_encoding +| 8 = @ruby_token_escape_sequence +| 9 = @ruby_token_false +| 10 = @ruby_token_file +| 11 = @ruby_token_float +| 12 = @ruby_token_forward_argument +| 13 = @ruby_token_forward_parameter +| 14 = @ruby_token_global_variable +| 15 = @ruby_token_hash_key_symbol +| 16 = @ruby_token_hash_splat_nil +| 17 = @ruby_token_heredoc_beginning +| 18 = @ruby_token_heredoc_content +| 19 = @ruby_token_heredoc_end +| 20 = @ruby_token_identifier +| 21 = @ruby_token_instance_variable +| 22 = @ruby_token_integer +| 23 = @ruby_token_line +| 24 = @ruby_token_nil +| 25 = @ruby_token_operator +| 26 = @ruby_token_self +| 27 = @ruby_token_simple_symbol +| 28 = @ruby_token_string_content +| 29 = @ruby_token_super +| 30 = @ruby_token_true +| 31 = @ruby_token_uninterpreted +; + + +@ruby_ast_node = @ruby_alias | @ruby_alternative_pattern | @ruby_argument_list | @ruby_array | @ruby_array_pattern | @ruby_as_pattern | @ruby_assignment | @ruby_bare_string | @ruby_bare_symbol | @ruby_begin | @ruby_begin_block | @ruby_binary | @ruby_block | @ruby_block_argument | @ruby_block_parameter | @ruby_block_parameters | @ruby_break | @ruby_call | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_conditional | @ruby_delimited_symbol | @ruby_destructured_left_assignment | @ruby_destructured_parameter | @ruby_do | @ruby_do_block | @ruby_element_reference | @ruby_else | @ruby_elsif | @ruby_end_block | @ruby_ensure | @ruby_exception_variable | @ruby_exceptions | @ruby_expression_reference_pattern | @ruby_find_pattern | @ruby_for | @ruby_hash | @ruby_hash_pattern | @ruby_hash_splat_argument | @ruby_hash_splat_parameter | @ruby_heredoc_body | @ruby_if | @ruby_if_guard | @ruby_if_modifier | @ruby_in | @ruby_in_clause | @ruby_interpolation | @ruby_keyword_parameter | @ruby_keyword_pattern | @ruby_lambda | @ruby_lambda_parameters | @ruby_left_assignment_list | @ruby_method | @ruby_method_parameters | @ruby_module | @ruby_next | @ruby_operator_assignment | @ruby_optional_parameter | @ruby_pair | @ruby_parenthesized_pattern | @ruby_parenthesized_statements | @ruby_pattern | @ruby_program | @ruby_range | @ruby_rational | @ruby_redo | @ruby_regex | @ruby_rescue | @ruby_rescue_modifier | @ruby_rest_assignment | @ruby_retry | @ruby_return | @ruby_right_assignment_list | @ruby_scope_resolution | @ruby_setter | @ruby_singleton_class | @ruby_singleton_method | @ruby_splat_argument | @ruby_splat_parameter | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_superclass | @ruby_symbol_array | @ruby_then | @ruby_token | @ruby_unary | @ruby_undef | @ruby_unless | @ruby_unless_guard | @ruby_unless_modifier | @ruby_until | @ruby_until_modifier | @ruby_variable_reference_pattern | @ruby_when | @ruby_while | @ruby_while_modifier | @ruby_yield + +@ruby_ast_node_parent = @file | @ruby_ast_node + +#keyset[parent, parent_index] +ruby_ast_node_info( + unique int node: @ruby_ast_node ref, + int parent: @ruby_ast_node_parent ref, + int parent_index: int ref, + int loc: @location ref +); + +erb_comment_directive_def( + unique int id: @erb_comment_directive, + int child: @erb_token_comment ref +); + +erb_directive_def( + unique int id: @erb_directive, + int child: @erb_token_code ref +); + +erb_graphql_directive_def( + unique int id: @erb_graphql_directive, + int child: @erb_token_code ref +); + +erb_output_directive_def( + unique int id: @erb_output_directive, + int child: @erb_token_code ref +); + +@erb_template_child_type = @erb_comment_directive | @erb_directive | @erb_graphql_directive | @erb_output_directive | @erb_token_content + +#keyset[erb_template, index] +erb_template_child( + int erb_template: @erb_template ref, + int index: int ref, + unique int child: @erb_template_child_type ref +); + +erb_template_def( + unique int id: @erb_template +); + +erb_tokeninfo( + unique int id: @erb_token, + int kind: int ref, + string value: string ref +); + +case @erb_token.kind of + 0 = @erb_reserved_word +| 1 = @erb_token_code +| 2 = @erb_token_comment +| 3 = @erb_token_content +; + + +@erb_ast_node = @erb_comment_directive | @erb_directive | @erb_graphql_directive | @erb_output_directive | @erb_template | @erb_token + +@erb_ast_node_parent = @erb_ast_node | @file + +#keyset[parent, parent_index] +erb_ast_node_info( + unique int node: @erb_ast_node ref, + int parent: @erb_ast_node_parent ref, + int parent_index: int ref, + int loc: @location ref +); + diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby.dbscheme b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby.dbscheme new file mode 100644 index 00000000000..1199e154f5e --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby.dbscheme @@ -0,0 +1,1417 @@ +// CodeQL database schema for Ruby +// Automatically generated from the tree-sitter grammar; do not edit + +@location = @location_default + +locations_default( + unique int id: @location_default, + int file: @file ref, + int start_line: int ref, + int start_column: int ref, + int end_line: int ref, + int end_column: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @file | @folder + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +sourceLocationPrefix( + string prefix: string ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +case @diagnostic.severity of + 10 = @diagnostic_debug +| 20 = @diagnostic_info +| 30 = @diagnostic_warning +| 40 = @diagnostic_error +; + + +@ruby_underscore_arg = @ruby_assignment | @ruby_binary | @ruby_conditional | @ruby_operator_assignment | @ruby_range | @ruby_unary | @ruby_underscore_primary + +@ruby_underscore_call_operator = @ruby_reserved_word + +@ruby_underscore_expression = @ruby_assignment | @ruby_binary | @ruby_break | @ruby_call | @ruby_next | @ruby_operator_assignment | @ruby_return | @ruby_unary | @ruby_underscore_arg | @ruby_yield + +@ruby_underscore_lhs = @ruby_call | @ruby_element_reference | @ruby_scope_resolution | @ruby_token_false | @ruby_token_nil | @ruby_token_true | @ruby_underscore_variable + +@ruby_underscore_method_name = @ruby_delimited_symbol | @ruby_setter | @ruby_token_constant | @ruby_token_identifier | @ruby_token_operator | @ruby_token_simple_symbol | @ruby_underscore_nonlocal_variable + +@ruby_underscore_nonlocal_variable = @ruby_token_class_variable | @ruby_token_global_variable | @ruby_token_instance_variable + +@ruby_underscore_pattern_constant = @ruby_scope_resolution | @ruby_token_constant + +@ruby_underscore_pattern_expr = @ruby_alternative_pattern | @ruby_as_pattern | @ruby_underscore_pattern_expr_basic + +@ruby_underscore_pattern_expr_basic = @ruby_array_pattern | @ruby_expression_reference_pattern | @ruby_find_pattern | @ruby_hash_pattern | @ruby_parenthesized_pattern | @ruby_range | @ruby_token_identifier | @ruby_underscore_pattern_constant | @ruby_underscore_pattern_primitive | @ruby_variable_reference_pattern + +@ruby_underscore_pattern_primitive = @ruby_delimited_symbol | @ruby_lambda | @ruby_regex | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_symbol_array | @ruby_token_encoding | @ruby_token_false | @ruby_token_file | @ruby_token_heredoc_beginning | @ruby_token_line | @ruby_token_nil | @ruby_token_self | @ruby_token_simple_symbol | @ruby_token_true | @ruby_unary | @ruby_underscore_simple_numeric + +@ruby_underscore_pattern_top_expr_body = @ruby_array_pattern | @ruby_find_pattern | @ruby_hash_pattern | @ruby_underscore_pattern_expr + +@ruby_underscore_primary = @ruby_array | @ruby_begin | @ruby_break | @ruby_call | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_delimited_symbol | @ruby_for | @ruby_hash | @ruby_if | @ruby_lambda | @ruby_method | @ruby_module | @ruby_next | @ruby_parenthesized_statements | @ruby_redo | @ruby_regex | @ruby_retry | @ruby_return | @ruby_singleton_class | @ruby_singleton_method | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_symbol_array | @ruby_token_character | @ruby_token_heredoc_beginning | @ruby_token_simple_symbol | @ruby_unary | @ruby_underscore_lhs | @ruby_underscore_simple_numeric | @ruby_unless | @ruby_until | @ruby_while | @ruby_yield + +@ruby_underscore_simple_numeric = @ruby_complex | @ruby_rational | @ruby_token_float | @ruby_token_integer + +@ruby_underscore_statement = @ruby_alias | @ruby_begin_block | @ruby_end_block | @ruby_if_modifier | @ruby_rescue_modifier | @ruby_undef | @ruby_underscore_expression | @ruby_unless_modifier | @ruby_until_modifier | @ruby_while_modifier + +@ruby_underscore_variable = @ruby_token_constant | @ruby_token_identifier | @ruby_token_self | @ruby_token_super | @ruby_underscore_nonlocal_variable + +ruby_alias_def( + unique int id: @ruby_alias, + int alias: @ruby_underscore_method_name ref, + int name: @ruby_underscore_method_name ref +); + +#keyset[ruby_alternative_pattern, index] +ruby_alternative_pattern_alternatives( + int ruby_alternative_pattern: @ruby_alternative_pattern ref, + int index: int ref, + unique int alternatives: @ruby_underscore_pattern_expr_basic ref +); + +ruby_alternative_pattern_def( + unique int id: @ruby_alternative_pattern +); + +@ruby_argument_list_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_argument_list, index] +ruby_argument_list_child( + int ruby_argument_list: @ruby_argument_list ref, + int index: int ref, + unique int child: @ruby_argument_list_child_type ref +); + +ruby_argument_list_def( + unique int id: @ruby_argument_list +); + +@ruby_array_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_array, index] +ruby_array_child( + int ruby_array: @ruby_array ref, + int index: int ref, + unique int child: @ruby_array_child_type ref +); + +ruby_array_def( + unique int id: @ruby_array +); + +ruby_array_pattern_class( + unique int ruby_array_pattern: @ruby_array_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_array_pattern_child_type = @ruby_splat_parameter | @ruby_underscore_pattern_expr + +#keyset[ruby_array_pattern, index] +ruby_array_pattern_child( + int ruby_array_pattern: @ruby_array_pattern ref, + int index: int ref, + unique int child: @ruby_array_pattern_child_type ref +); + +ruby_array_pattern_def( + unique int id: @ruby_array_pattern +); + +ruby_as_pattern_def( + unique int id: @ruby_as_pattern, + int name: @ruby_token_identifier ref, + int value: @ruby_underscore_pattern_expr ref +); + +@ruby_assignment_left_type = @ruby_left_assignment_list | @ruby_underscore_lhs + +@ruby_assignment_right_type = @ruby_rescue_modifier | @ruby_right_assignment_list | @ruby_splat_argument | @ruby_underscore_expression + +ruby_assignment_def( + unique int id: @ruby_assignment, + int left: @ruby_assignment_left_type ref, + int right: @ruby_assignment_right_type ref +); + +@ruby_bare_string_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_bare_string, index] +ruby_bare_string_child( + int ruby_bare_string: @ruby_bare_string ref, + int index: int ref, + unique int child: @ruby_bare_string_child_type ref +); + +ruby_bare_string_def( + unique int id: @ruby_bare_string +); + +@ruby_bare_symbol_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_bare_symbol, index] +ruby_bare_symbol_child( + int ruby_bare_symbol: @ruby_bare_symbol ref, + int index: int ref, + unique int child: @ruby_bare_symbol_child_type ref +); + +ruby_bare_symbol_def( + unique int id: @ruby_bare_symbol +); + +@ruby_begin_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_begin, index] +ruby_begin_child( + int ruby_begin: @ruby_begin ref, + int index: int ref, + unique int child: @ruby_begin_child_type ref +); + +ruby_begin_def( + unique int id: @ruby_begin +); + +@ruby_begin_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_begin_block, index] +ruby_begin_block_child( + int ruby_begin_block: @ruby_begin_block ref, + int index: int ref, + unique int child: @ruby_begin_block_child_type ref +); + +ruby_begin_block_def( + unique int id: @ruby_begin_block +); + +@ruby_binary_left_type = @ruby_underscore_expression | @ruby_underscore_simple_numeric + +case @ruby_binary.operator of + 0 = @ruby_binary_bangequal +| 1 = @ruby_binary_bangtilde +| 2 = @ruby_binary_percent +| 3 = @ruby_binary_ampersand +| 4 = @ruby_binary_ampersandampersand +| 5 = @ruby_binary_star +| 6 = @ruby_binary_starstar +| 7 = @ruby_binary_plus +| 8 = @ruby_binary_minus +| 9 = @ruby_binary_slash +| 10 = @ruby_binary_langle +| 11 = @ruby_binary_langlelangle +| 12 = @ruby_binary_langleequal +| 13 = @ruby_binary_langleequalrangle +| 14 = @ruby_binary_equalequal +| 15 = @ruby_binary_equalequalequal +| 16 = @ruby_binary_equaltilde +| 17 = @ruby_binary_rangle +| 18 = @ruby_binary_rangleequal +| 19 = @ruby_binary_ranglerangle +| 20 = @ruby_binary_caret +| 21 = @ruby_binary_and +| 22 = @ruby_binary_or +| 23 = @ruby_binary_pipe +| 24 = @ruby_binary_pipepipe +; + + +ruby_binary_def( + unique int id: @ruby_binary, + int left: @ruby_binary_left_type ref, + int operator: int ref, + int right: @ruby_underscore_expression ref +); + +ruby_block_parameters( + unique int ruby_block: @ruby_block ref, + unique int parameters: @ruby_block_parameters ref +); + +@ruby_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_block, index] +ruby_block_child( + int ruby_block: @ruby_block ref, + int index: int ref, + unique int child: @ruby_block_child_type ref +); + +ruby_block_def( + unique int id: @ruby_block +); + +ruby_block_argument_child( + unique int ruby_block_argument: @ruby_block_argument ref, + unique int child: @ruby_underscore_arg ref +); + +ruby_block_argument_def( + unique int id: @ruby_block_argument +); + +ruby_block_parameter_name( + unique int ruby_block_parameter: @ruby_block_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_block_parameter_def( + unique int id: @ruby_block_parameter +); + +#keyset[ruby_block_parameters, index] +ruby_block_parameters_locals( + int ruby_block_parameters: @ruby_block_parameters ref, + int index: int ref, + unique int locals: @ruby_token_identifier ref +); + +@ruby_block_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_block_parameters, index] +ruby_block_parameters_child( + int ruby_block_parameters: @ruby_block_parameters ref, + int index: int ref, + unique int child: @ruby_block_parameters_child_type ref +); + +ruby_block_parameters_def( + unique int id: @ruby_block_parameters +); + +ruby_break_child( + unique int ruby_break: @ruby_break ref, + unique int child: @ruby_argument_list ref +); + +ruby_break_def( + unique int id: @ruby_break +); + +ruby_call_arguments( + unique int ruby_call: @ruby_call ref, + unique int arguments: @ruby_argument_list ref +); + +@ruby_call_block_type = @ruby_block | @ruby_do_block + +ruby_call_block( + unique int ruby_call: @ruby_call ref, + unique int block: @ruby_call_block_type ref +); + +@ruby_call_method_type = @ruby_token_operator | @ruby_underscore_variable + +ruby_call_method( + unique int ruby_call: @ruby_call ref, + unique int method: @ruby_call_method_type ref +); + +ruby_call_operator( + unique int ruby_call: @ruby_call ref, + unique int operator: @ruby_underscore_call_operator ref +); + +ruby_call_receiver( + unique int ruby_call: @ruby_call ref, + unique int receiver: @ruby_underscore_primary ref +); + +ruby_call_def( + unique int id: @ruby_call +); + +ruby_case_value( + unique int ruby_case__: @ruby_case__ ref, + unique int value: @ruby_underscore_statement ref +); + +@ruby_case_child_type = @ruby_else | @ruby_when + +#keyset[ruby_case__, index] +ruby_case_child( + int ruby_case__: @ruby_case__ ref, + int index: int ref, + unique int child: @ruby_case_child_type ref +); + +ruby_case_def( + unique int id: @ruby_case__ +); + +#keyset[ruby_case_match, index] +ruby_case_match_clauses( + int ruby_case_match: @ruby_case_match ref, + int index: int ref, + unique int clauses: @ruby_in_clause ref +); + +ruby_case_match_else( + unique int ruby_case_match: @ruby_case_match ref, + unique int else: @ruby_else ref +); + +ruby_case_match_def( + unique int id: @ruby_case_match, + int value: @ruby_underscore_statement ref +); + +#keyset[ruby_chained_string, index] +ruby_chained_string_child( + int ruby_chained_string: @ruby_chained_string ref, + int index: int ref, + unique int child: @ruby_string__ ref +); + +ruby_chained_string_def( + unique int id: @ruby_chained_string +); + +@ruby_class_name_type = @ruby_scope_resolution | @ruby_token_constant + +ruby_class_superclass( + unique int ruby_class: @ruby_class ref, + unique int superclass: @ruby_superclass ref +); + +@ruby_class_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_class, index] +ruby_class_child( + int ruby_class: @ruby_class ref, + int index: int ref, + unique int child: @ruby_class_child_type ref +); + +ruby_class_def( + unique int id: @ruby_class, + int name: @ruby_class_name_type ref +); + +@ruby_complex_child_type = @ruby_rational | @ruby_token_float | @ruby_token_integer + +ruby_complex_def( + unique int id: @ruby_complex, + int child: @ruby_complex_child_type ref +); + +ruby_conditional_def( + unique int id: @ruby_conditional, + int alternative: @ruby_underscore_arg ref, + int condition: @ruby_underscore_arg ref, + int consequence: @ruby_underscore_arg ref +); + +@ruby_delimited_symbol_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_delimited_symbol, index] +ruby_delimited_symbol_child( + int ruby_delimited_symbol: @ruby_delimited_symbol ref, + int index: int ref, + unique int child: @ruby_delimited_symbol_child_type ref +); + +ruby_delimited_symbol_def( + unique int id: @ruby_delimited_symbol +); + +@ruby_destructured_left_assignment_child_type = @ruby_destructured_left_assignment | @ruby_rest_assignment | @ruby_underscore_lhs + +#keyset[ruby_destructured_left_assignment, index] +ruby_destructured_left_assignment_child( + int ruby_destructured_left_assignment: @ruby_destructured_left_assignment ref, + int index: int ref, + unique int child: @ruby_destructured_left_assignment_child_type ref +); + +ruby_destructured_left_assignment_def( + unique int id: @ruby_destructured_left_assignment +); + +@ruby_destructured_parameter_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_destructured_parameter, index] +ruby_destructured_parameter_child( + int ruby_destructured_parameter: @ruby_destructured_parameter ref, + int index: int ref, + unique int child: @ruby_destructured_parameter_child_type ref +); + +ruby_destructured_parameter_def( + unique int id: @ruby_destructured_parameter +); + +@ruby_do_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_do, index] +ruby_do_child( + int ruby_do: @ruby_do ref, + int index: int ref, + unique int child: @ruby_do_child_type ref +); + +ruby_do_def( + unique int id: @ruby_do +); + +ruby_do_block_parameters( + unique int ruby_do_block: @ruby_do_block ref, + unique int parameters: @ruby_block_parameters ref +); + +@ruby_do_block_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_do_block, index] +ruby_do_block_child( + int ruby_do_block: @ruby_do_block ref, + int index: int ref, + unique int child: @ruby_do_block_child_type ref +); + +ruby_do_block_def( + unique int id: @ruby_do_block +); + +@ruby_element_reference_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression + +#keyset[ruby_element_reference, index] +ruby_element_reference_child( + int ruby_element_reference: @ruby_element_reference ref, + int index: int ref, + unique int child: @ruby_element_reference_child_type ref +); + +ruby_element_reference_def( + unique int id: @ruby_element_reference, + int object: @ruby_underscore_primary ref +); + +@ruby_else_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_else, index] +ruby_else_child( + int ruby_else: @ruby_else ref, + int index: int ref, + unique int child: @ruby_else_child_type ref +); + +ruby_else_def( + unique int id: @ruby_else +); + +@ruby_elsif_alternative_type = @ruby_else | @ruby_elsif + +ruby_elsif_alternative( + unique int ruby_elsif: @ruby_elsif ref, + unique int alternative: @ruby_elsif_alternative_type ref +); + +ruby_elsif_consequence( + unique int ruby_elsif: @ruby_elsif ref, + unique int consequence: @ruby_then ref +); + +ruby_elsif_def( + unique int id: @ruby_elsif, + int condition: @ruby_underscore_statement ref +); + +@ruby_end_block_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_end_block, index] +ruby_end_block_child( + int ruby_end_block: @ruby_end_block ref, + int index: int ref, + unique int child: @ruby_end_block_child_type ref +); + +ruby_end_block_def( + unique int id: @ruby_end_block +); + +@ruby_ensure_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_ensure, index] +ruby_ensure_child( + int ruby_ensure: @ruby_ensure ref, + int index: int ref, + unique int child: @ruby_ensure_child_type ref +); + +ruby_ensure_def( + unique int id: @ruby_ensure +); + +ruby_exception_variable_def( + unique int id: @ruby_exception_variable, + int child: @ruby_underscore_lhs ref +); + +@ruby_exceptions_child_type = @ruby_splat_argument | @ruby_underscore_arg + +#keyset[ruby_exceptions, index] +ruby_exceptions_child( + int ruby_exceptions: @ruby_exceptions ref, + int index: int ref, + unique int child: @ruby_exceptions_child_type ref +); + +ruby_exceptions_def( + unique int id: @ruby_exceptions +); + +ruby_expression_reference_pattern_def( + unique int id: @ruby_expression_reference_pattern, + int value: @ruby_underscore_expression ref +); + +ruby_find_pattern_class( + unique int ruby_find_pattern: @ruby_find_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_find_pattern_child_type = @ruby_splat_parameter | @ruby_underscore_pattern_expr + +#keyset[ruby_find_pattern, index] +ruby_find_pattern_child( + int ruby_find_pattern: @ruby_find_pattern ref, + int index: int ref, + unique int child: @ruby_find_pattern_child_type ref +); + +ruby_find_pattern_def( + unique int id: @ruby_find_pattern +); + +@ruby_for_pattern_type = @ruby_left_assignment_list | @ruby_underscore_lhs + +ruby_for_def( + unique int id: @ruby_for, + int body: @ruby_do ref, + int pattern: @ruby_for_pattern_type ref, + int value: @ruby_in ref +); + +@ruby_hash_child_type = @ruby_hash_splat_argument | @ruby_pair + +#keyset[ruby_hash, index] +ruby_hash_child( + int ruby_hash: @ruby_hash ref, + int index: int ref, + unique int child: @ruby_hash_child_type ref +); + +ruby_hash_def( + unique int id: @ruby_hash +); + +ruby_hash_pattern_class( + unique int ruby_hash_pattern: @ruby_hash_pattern ref, + unique int class: @ruby_underscore_pattern_constant ref +); + +@ruby_hash_pattern_child_type = @ruby_hash_splat_parameter | @ruby_keyword_pattern | @ruby_token_hash_splat_nil + +#keyset[ruby_hash_pattern, index] +ruby_hash_pattern_child( + int ruby_hash_pattern: @ruby_hash_pattern ref, + int index: int ref, + unique int child: @ruby_hash_pattern_child_type ref +); + +ruby_hash_pattern_def( + unique int id: @ruby_hash_pattern +); + +ruby_hash_splat_argument_def( + unique int id: @ruby_hash_splat_argument, + int child: @ruby_underscore_arg ref +); + +ruby_hash_splat_parameter_name( + unique int ruby_hash_splat_parameter: @ruby_hash_splat_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_hash_splat_parameter_def( + unique int id: @ruby_hash_splat_parameter +); + +@ruby_heredoc_body_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_heredoc_content | @ruby_token_heredoc_end + +#keyset[ruby_heredoc_body, index] +ruby_heredoc_body_child( + int ruby_heredoc_body: @ruby_heredoc_body ref, + int index: int ref, + unique int child: @ruby_heredoc_body_child_type ref +); + +ruby_heredoc_body_def( + unique int id: @ruby_heredoc_body +); + +@ruby_if_alternative_type = @ruby_else | @ruby_elsif + +ruby_if_alternative( + unique int ruby_if: @ruby_if ref, + unique int alternative: @ruby_if_alternative_type ref +); + +ruby_if_consequence( + unique int ruby_if: @ruby_if ref, + unique int consequence: @ruby_then ref +); + +ruby_if_def( + unique int id: @ruby_if, + int condition: @ruby_underscore_statement ref +); + +ruby_if_guard_def( + unique int id: @ruby_if_guard, + int condition: @ruby_underscore_expression ref +); + +ruby_if_modifier_def( + unique int id: @ruby_if_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_in_def( + unique int id: @ruby_in, + int child: @ruby_underscore_arg ref +); + +ruby_in_clause_body( + unique int ruby_in_clause: @ruby_in_clause ref, + unique int body: @ruby_then ref +); + +@ruby_in_clause_guard_type = @ruby_if_guard | @ruby_unless_guard + +ruby_in_clause_guard( + unique int ruby_in_clause: @ruby_in_clause ref, + unique int guard: @ruby_in_clause_guard_type ref +); + +ruby_in_clause_def( + unique int id: @ruby_in_clause, + int pattern: @ruby_underscore_pattern_top_expr_body ref +); + +@ruby_interpolation_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_interpolation, index] +ruby_interpolation_child( + int ruby_interpolation: @ruby_interpolation ref, + int index: int ref, + unique int child: @ruby_interpolation_child_type ref +); + +ruby_interpolation_def( + unique int id: @ruby_interpolation +); + +ruby_keyword_parameter_value( + unique int ruby_keyword_parameter: @ruby_keyword_parameter ref, + unique int value: @ruby_underscore_arg ref +); + +ruby_keyword_parameter_def( + unique int id: @ruby_keyword_parameter, + int name: @ruby_token_identifier ref +); + +@ruby_keyword_pattern_key_type = @ruby_string__ | @ruby_token_hash_key_symbol + +ruby_keyword_pattern_value( + unique int ruby_keyword_pattern: @ruby_keyword_pattern ref, + unique int value: @ruby_underscore_pattern_expr ref +); + +ruby_keyword_pattern_def( + unique int id: @ruby_keyword_pattern, + int key__: @ruby_keyword_pattern_key_type ref +); + +@ruby_lambda_body_type = @ruby_block | @ruby_do_block + +ruby_lambda_parameters( + unique int ruby_lambda: @ruby_lambda ref, + unique int parameters: @ruby_lambda_parameters ref +); + +ruby_lambda_def( + unique int id: @ruby_lambda, + int body: @ruby_lambda_body_type ref +); + +@ruby_lambda_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_lambda_parameters, index] +ruby_lambda_parameters_child( + int ruby_lambda_parameters: @ruby_lambda_parameters ref, + int index: int ref, + unique int child: @ruby_lambda_parameters_child_type ref +); + +ruby_lambda_parameters_def( + unique int id: @ruby_lambda_parameters +); + +@ruby_left_assignment_list_child_type = @ruby_destructured_left_assignment | @ruby_rest_assignment | @ruby_underscore_lhs + +#keyset[ruby_left_assignment_list, index] +ruby_left_assignment_list_child( + int ruby_left_assignment_list: @ruby_left_assignment_list ref, + int index: int ref, + unique int child: @ruby_left_assignment_list_child_type ref +); + +ruby_left_assignment_list_def( + unique int id: @ruby_left_assignment_list +); + +ruby_method_parameters( + unique int ruby_method: @ruby_method ref, + unique int parameters: @ruby_method_parameters ref +); + +@ruby_method_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_arg | @ruby_underscore_statement + +#keyset[ruby_method, index] +ruby_method_child( + int ruby_method: @ruby_method ref, + int index: int ref, + unique int child: @ruby_method_child_type ref +); + +ruby_method_def( + unique int id: @ruby_method, + int name: @ruby_underscore_method_name ref +); + +@ruby_method_parameters_child_type = @ruby_block_parameter | @ruby_destructured_parameter | @ruby_hash_splat_parameter | @ruby_keyword_parameter | @ruby_optional_parameter | @ruby_splat_parameter | @ruby_token_forward_parameter | @ruby_token_hash_splat_nil | @ruby_token_identifier + +#keyset[ruby_method_parameters, index] +ruby_method_parameters_child( + int ruby_method_parameters: @ruby_method_parameters ref, + int index: int ref, + unique int child: @ruby_method_parameters_child_type ref +); + +ruby_method_parameters_def( + unique int id: @ruby_method_parameters +); + +@ruby_module_name_type = @ruby_scope_resolution | @ruby_token_constant + +@ruby_module_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_module, index] +ruby_module_child( + int ruby_module: @ruby_module ref, + int index: int ref, + unique int child: @ruby_module_child_type ref +); + +ruby_module_def( + unique int id: @ruby_module, + int name: @ruby_module_name_type ref +); + +ruby_next_child( + unique int ruby_next: @ruby_next ref, + unique int child: @ruby_argument_list ref +); + +ruby_next_def( + unique int id: @ruby_next +); + +case @ruby_operator_assignment.operator of + 0 = @ruby_operator_assignment_percentequal +| 1 = @ruby_operator_assignment_ampersandampersandequal +| 2 = @ruby_operator_assignment_ampersandequal +| 3 = @ruby_operator_assignment_starstarequal +| 4 = @ruby_operator_assignment_starequal +| 5 = @ruby_operator_assignment_plusequal +| 6 = @ruby_operator_assignment_minusequal +| 7 = @ruby_operator_assignment_slashequal +| 8 = @ruby_operator_assignment_langlelangleequal +| 9 = @ruby_operator_assignment_ranglerangleequal +| 10 = @ruby_operator_assignment_caretequal +| 11 = @ruby_operator_assignment_pipeequal +| 12 = @ruby_operator_assignment_pipepipeequal +; + + +@ruby_operator_assignment_right_type = @ruby_rescue_modifier | @ruby_underscore_expression + +ruby_operator_assignment_def( + unique int id: @ruby_operator_assignment, + int left: @ruby_underscore_lhs ref, + int operator: int ref, + int right: @ruby_operator_assignment_right_type ref +); + +ruby_optional_parameter_def( + unique int id: @ruby_optional_parameter, + int name: @ruby_token_identifier ref, + int value: @ruby_underscore_arg ref +); + +@ruby_pair_key_type = @ruby_string__ | @ruby_token_hash_key_symbol | @ruby_underscore_arg + +ruby_pair_value( + unique int ruby_pair: @ruby_pair ref, + unique int value: @ruby_underscore_arg ref +); + +ruby_pair_def( + unique int id: @ruby_pair, + int key__: @ruby_pair_key_type ref +); + +ruby_parenthesized_pattern_def( + unique int id: @ruby_parenthesized_pattern, + int child: @ruby_underscore_pattern_expr ref +); + +@ruby_parenthesized_statements_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_parenthesized_statements, index] +ruby_parenthesized_statements_child( + int ruby_parenthesized_statements: @ruby_parenthesized_statements ref, + int index: int ref, + unique int child: @ruby_parenthesized_statements_child_type ref +); + +ruby_parenthesized_statements_def( + unique int id: @ruby_parenthesized_statements +); + +@ruby_pattern_child_type = @ruby_splat_argument | @ruby_underscore_arg + +ruby_pattern_def( + unique int id: @ruby_pattern, + int child: @ruby_pattern_child_type ref +); + +@ruby_program_child_type = @ruby_token_empty_statement | @ruby_token_uninterpreted | @ruby_underscore_statement + +#keyset[ruby_program, index] +ruby_program_child( + int ruby_program: @ruby_program ref, + int index: int ref, + unique int child: @ruby_program_child_type ref +); + +ruby_program_def( + unique int id: @ruby_program +); + +@ruby_range_begin_type = @ruby_underscore_arg | @ruby_underscore_pattern_primitive + +ruby_range_begin( + unique int ruby_range: @ruby_range ref, + unique int begin: @ruby_range_begin_type ref +); + +@ruby_range_end_type = @ruby_underscore_arg | @ruby_underscore_pattern_primitive + +ruby_range_end( + unique int ruby_range: @ruby_range ref, + unique int end: @ruby_range_end_type ref +); + +case @ruby_range.operator of + 0 = @ruby_range_dotdot +| 1 = @ruby_range_dotdotdot +; + + +ruby_range_def( + unique int id: @ruby_range, + int operator: int ref +); + +@ruby_rational_child_type = @ruby_token_float | @ruby_token_integer + +ruby_rational_def( + unique int id: @ruby_rational, + int child: @ruby_rational_child_type ref +); + +ruby_redo_child( + unique int ruby_redo: @ruby_redo ref, + unique int child: @ruby_argument_list ref +); + +ruby_redo_def( + unique int id: @ruby_redo +); + +@ruby_regex_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_regex, index] +ruby_regex_child( + int ruby_regex: @ruby_regex ref, + int index: int ref, + unique int child: @ruby_regex_child_type ref +); + +ruby_regex_def( + unique int id: @ruby_regex +); + +ruby_rescue_body( + unique int ruby_rescue: @ruby_rescue ref, + unique int body: @ruby_then ref +); + +ruby_rescue_exceptions( + unique int ruby_rescue: @ruby_rescue ref, + unique int exceptions: @ruby_exceptions ref +); + +ruby_rescue_variable( + unique int ruby_rescue: @ruby_rescue ref, + unique int variable: @ruby_exception_variable ref +); + +ruby_rescue_def( + unique int id: @ruby_rescue +); + +@ruby_rescue_modifier_body_type = @ruby_underscore_arg | @ruby_underscore_statement + +ruby_rescue_modifier_def( + unique int id: @ruby_rescue_modifier, + int body: @ruby_rescue_modifier_body_type ref, + int handler: @ruby_underscore_expression ref +); + +ruby_rest_assignment_child( + unique int ruby_rest_assignment: @ruby_rest_assignment ref, + unique int child: @ruby_underscore_lhs ref +); + +ruby_rest_assignment_def( + unique int id: @ruby_rest_assignment +); + +ruby_retry_child( + unique int ruby_retry: @ruby_retry ref, + unique int child: @ruby_argument_list ref +); + +ruby_retry_def( + unique int id: @ruby_retry +); + +ruby_return_child( + unique int ruby_return: @ruby_return ref, + unique int child: @ruby_argument_list ref +); + +ruby_return_def( + unique int id: @ruby_return +); + +@ruby_right_assignment_list_child_type = @ruby_splat_argument | @ruby_underscore_arg + +#keyset[ruby_right_assignment_list, index] +ruby_right_assignment_list_child( + int ruby_right_assignment_list: @ruby_right_assignment_list ref, + int index: int ref, + unique int child: @ruby_right_assignment_list_child_type ref +); + +ruby_right_assignment_list_def( + unique int id: @ruby_right_assignment_list +); + +@ruby_scope_resolution_scope_type = @ruby_underscore_pattern_constant | @ruby_underscore_primary + +ruby_scope_resolution_scope( + unique int ruby_scope_resolution: @ruby_scope_resolution ref, + unique int scope: @ruby_scope_resolution_scope_type ref +); + +ruby_scope_resolution_def( + unique int id: @ruby_scope_resolution, + int name: @ruby_token_constant ref +); + +ruby_setter_def( + unique int id: @ruby_setter, + int name: @ruby_token_identifier ref +); + +@ruby_singleton_class_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_singleton_class, index] +ruby_singleton_class_child( + int ruby_singleton_class: @ruby_singleton_class ref, + int index: int ref, + unique int child: @ruby_singleton_class_child_type ref +); + +ruby_singleton_class_def( + unique int id: @ruby_singleton_class, + int value: @ruby_underscore_arg ref +); + +@ruby_singleton_method_object_type = @ruby_underscore_arg | @ruby_underscore_variable + +ruby_singleton_method_parameters( + unique int ruby_singleton_method: @ruby_singleton_method ref, + unique int parameters: @ruby_method_parameters ref +); + +@ruby_singleton_method_child_type = @ruby_else | @ruby_ensure | @ruby_rescue | @ruby_token_empty_statement | @ruby_underscore_arg | @ruby_underscore_statement + +#keyset[ruby_singleton_method, index] +ruby_singleton_method_child( + int ruby_singleton_method: @ruby_singleton_method ref, + int index: int ref, + unique int child: @ruby_singleton_method_child_type ref +); + +ruby_singleton_method_def( + unique int id: @ruby_singleton_method, + int name: @ruby_underscore_method_name ref, + int object: @ruby_singleton_method_object_type ref +); + +ruby_splat_argument_def( + unique int id: @ruby_splat_argument, + int child: @ruby_underscore_arg ref +); + +ruby_splat_parameter_name( + unique int ruby_splat_parameter: @ruby_splat_parameter ref, + unique int name: @ruby_token_identifier ref +); + +ruby_splat_parameter_def( + unique int id: @ruby_splat_parameter +); + +@ruby_string_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_string__, index] +ruby_string_child( + int ruby_string__: @ruby_string__ ref, + int index: int ref, + unique int child: @ruby_string_child_type ref +); + +ruby_string_def( + unique int id: @ruby_string__ +); + +#keyset[ruby_string_array, index] +ruby_string_array_child( + int ruby_string_array: @ruby_string_array ref, + int index: int ref, + unique int child: @ruby_bare_string ref +); + +ruby_string_array_def( + unique int id: @ruby_string_array +); + +@ruby_subshell_child_type = @ruby_interpolation | @ruby_token_escape_sequence | @ruby_token_string_content + +#keyset[ruby_subshell, index] +ruby_subshell_child( + int ruby_subshell: @ruby_subshell ref, + int index: int ref, + unique int child: @ruby_subshell_child_type ref +); + +ruby_subshell_def( + unique int id: @ruby_subshell +); + +ruby_superclass_def( + unique int id: @ruby_superclass, + int child: @ruby_underscore_expression ref +); + +#keyset[ruby_symbol_array, index] +ruby_symbol_array_child( + int ruby_symbol_array: @ruby_symbol_array ref, + int index: int ref, + unique int child: @ruby_bare_symbol ref +); + +ruby_symbol_array_def( + unique int id: @ruby_symbol_array +); + +@ruby_then_child_type = @ruby_token_empty_statement | @ruby_underscore_statement + +#keyset[ruby_then, index] +ruby_then_child( + int ruby_then: @ruby_then ref, + int index: int ref, + unique int child: @ruby_then_child_type ref +); + +ruby_then_def( + unique int id: @ruby_then +); + +@ruby_unary_operand_type = @ruby_parenthesized_statements | @ruby_underscore_expression | @ruby_underscore_simple_numeric + +case @ruby_unary.operator of + 0 = @ruby_unary_bang +| 1 = @ruby_unary_plus +| 2 = @ruby_unary_minus +| 3 = @ruby_unary_definedquestion +| 4 = @ruby_unary_not +| 5 = @ruby_unary_tilde +; + + +ruby_unary_def( + unique int id: @ruby_unary, + int operand: @ruby_unary_operand_type ref, + int operator: int ref +); + +#keyset[ruby_undef, index] +ruby_undef_child( + int ruby_undef: @ruby_undef ref, + int index: int ref, + unique int child: @ruby_underscore_method_name ref +); + +ruby_undef_def( + unique int id: @ruby_undef +); + +@ruby_unless_alternative_type = @ruby_else | @ruby_elsif + +ruby_unless_alternative( + unique int ruby_unless: @ruby_unless ref, + unique int alternative: @ruby_unless_alternative_type ref +); + +ruby_unless_consequence( + unique int ruby_unless: @ruby_unless ref, + unique int consequence: @ruby_then ref +); + +ruby_unless_def( + unique int id: @ruby_unless, + int condition: @ruby_underscore_statement ref +); + +ruby_unless_guard_def( + unique int id: @ruby_unless_guard, + int condition: @ruby_underscore_expression ref +); + +ruby_unless_modifier_def( + unique int id: @ruby_unless_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_until_def( + unique int id: @ruby_until, + int body: @ruby_do ref, + int condition: @ruby_underscore_statement ref +); + +ruby_until_modifier_def( + unique int id: @ruby_until_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +@ruby_variable_reference_pattern_name_type = @ruby_token_identifier | @ruby_underscore_nonlocal_variable + +ruby_variable_reference_pattern_def( + unique int id: @ruby_variable_reference_pattern, + int name: @ruby_variable_reference_pattern_name_type ref +); + +ruby_when_body( + unique int ruby_when: @ruby_when ref, + unique int body: @ruby_then ref +); + +#keyset[ruby_when, index] +ruby_when_pattern( + int ruby_when: @ruby_when ref, + int index: int ref, + unique int pattern: @ruby_pattern ref +); + +ruby_when_def( + unique int id: @ruby_when +); + +ruby_while_def( + unique int id: @ruby_while, + int body: @ruby_do ref, + int condition: @ruby_underscore_statement ref +); + +ruby_while_modifier_def( + unique int id: @ruby_while_modifier, + int body: @ruby_underscore_statement ref, + int condition: @ruby_underscore_expression ref +); + +ruby_yield_child( + unique int ruby_yield: @ruby_yield ref, + unique int child: @ruby_argument_list ref +); + +ruby_yield_def( + unique int id: @ruby_yield +); + +ruby_tokeninfo( + unique int id: @ruby_token, + int kind: int ref, + string value: string ref +); + +case @ruby_token.kind of + 0 = @ruby_reserved_word +| 1 = @ruby_token_character +| 2 = @ruby_token_class_variable +| 3 = @ruby_token_comment +| 4 = @ruby_token_constant +| 5 = @ruby_token_empty_statement +| 6 = @ruby_token_encoding +| 7 = @ruby_token_escape_sequence +| 8 = @ruby_token_false +| 9 = @ruby_token_file +| 10 = @ruby_token_float +| 11 = @ruby_token_forward_argument +| 12 = @ruby_token_forward_parameter +| 13 = @ruby_token_global_variable +| 14 = @ruby_token_hash_key_symbol +| 15 = @ruby_token_hash_splat_nil +| 16 = @ruby_token_heredoc_beginning +| 17 = @ruby_token_heredoc_content +| 18 = @ruby_token_heredoc_end +| 19 = @ruby_token_identifier +| 20 = @ruby_token_instance_variable +| 21 = @ruby_token_integer +| 22 = @ruby_token_line +| 23 = @ruby_token_nil +| 24 = @ruby_token_operator +| 25 = @ruby_token_self +| 26 = @ruby_token_simple_symbol +| 27 = @ruby_token_string_content +| 28 = @ruby_token_super +| 29 = @ruby_token_true +| 30 = @ruby_token_uninterpreted +; + + +@ruby_ast_node = @ruby_alias | @ruby_alternative_pattern | @ruby_argument_list | @ruby_array | @ruby_array_pattern | @ruby_as_pattern | @ruby_assignment | @ruby_bare_string | @ruby_bare_symbol | @ruby_begin | @ruby_begin_block | @ruby_binary | @ruby_block | @ruby_block_argument | @ruby_block_parameter | @ruby_block_parameters | @ruby_break | @ruby_call | @ruby_case__ | @ruby_case_match | @ruby_chained_string | @ruby_class | @ruby_complex | @ruby_conditional | @ruby_delimited_symbol | @ruby_destructured_left_assignment | @ruby_destructured_parameter | @ruby_do | @ruby_do_block | @ruby_element_reference | @ruby_else | @ruby_elsif | @ruby_end_block | @ruby_ensure | @ruby_exception_variable | @ruby_exceptions | @ruby_expression_reference_pattern | @ruby_find_pattern | @ruby_for | @ruby_hash | @ruby_hash_pattern | @ruby_hash_splat_argument | @ruby_hash_splat_parameter | @ruby_heredoc_body | @ruby_if | @ruby_if_guard | @ruby_if_modifier | @ruby_in | @ruby_in_clause | @ruby_interpolation | @ruby_keyword_parameter | @ruby_keyword_pattern | @ruby_lambda | @ruby_lambda_parameters | @ruby_left_assignment_list | @ruby_method | @ruby_method_parameters | @ruby_module | @ruby_next | @ruby_operator_assignment | @ruby_optional_parameter | @ruby_pair | @ruby_parenthesized_pattern | @ruby_parenthesized_statements | @ruby_pattern | @ruby_program | @ruby_range | @ruby_rational | @ruby_redo | @ruby_regex | @ruby_rescue | @ruby_rescue_modifier | @ruby_rest_assignment | @ruby_retry | @ruby_return | @ruby_right_assignment_list | @ruby_scope_resolution | @ruby_setter | @ruby_singleton_class | @ruby_singleton_method | @ruby_splat_argument | @ruby_splat_parameter | @ruby_string__ | @ruby_string_array | @ruby_subshell | @ruby_superclass | @ruby_symbol_array | @ruby_then | @ruby_token | @ruby_unary | @ruby_undef | @ruby_unless | @ruby_unless_guard | @ruby_unless_modifier | @ruby_until | @ruby_until_modifier | @ruby_variable_reference_pattern | @ruby_when | @ruby_while | @ruby_while_modifier | @ruby_yield + +@ruby_ast_node_parent = @file | @ruby_ast_node + +#keyset[parent, parent_index] +ruby_ast_node_info( + unique int node: @ruby_ast_node ref, + int parent: @ruby_ast_node_parent ref, + int parent_index: int ref, + int loc: @location ref +); + +erb_comment_directive_def( + unique int id: @erb_comment_directive, + int child: @erb_token_comment ref +); + +erb_directive_def( + unique int id: @erb_directive, + int child: @erb_token_code ref +); + +erb_graphql_directive_def( + unique int id: @erb_graphql_directive, + int child: @erb_token_code ref +); + +erb_output_directive_def( + unique int id: @erb_output_directive, + int child: @erb_token_code ref +); + +@erb_template_child_type = @erb_comment_directive | @erb_directive | @erb_graphql_directive | @erb_output_directive | @erb_token_content + +#keyset[erb_template, index] +erb_template_child( + int erb_template: @erb_template ref, + int index: int ref, + unique int child: @erb_template_child_type ref +); + +erb_template_def( + unique int id: @erb_template +); + +erb_tokeninfo( + unique int id: @erb_token, + int kind: int ref, + string value: string ref +); + +case @erb_token.kind of + 0 = @erb_reserved_word +| 1 = @erb_token_code +| 2 = @erb_token_comment +| 3 = @erb_token_content +; + + +@erb_ast_node = @erb_comment_directive | @erb_directive | @erb_graphql_directive | @erb_output_directive | @erb_template | @erb_token + +@erb_ast_node_parent = @erb_ast_node | @file + +#keyset[parent, parent_index] +erb_ast_node_info( + unique int node: @erb_ast_node ref, + int parent: @erb_ast_node_parent ref, + int parent_index: int ref, + int loc: @location ref +); + diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_ast_node_info.ql b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_ast_node_info.ql new file mode 100644 index 00000000000..18cff225540 --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_ast_node_info.ql @@ -0,0 +1,45 @@ +class ScopeResolutionMethodCall extends @ruby_call { + private @ruby_scope_resolution scope; + + ScopeResolutionMethodCall() { ruby_call_def(this, scope) } + + @ruby_scope_resolution getScopeResolution() { result = scope } + + string toString() { none() } +} + +class Location extends @location { + string toString() { none() } +} + +class RubyAstNode extends @ruby_ast_node { + string toString() { none() } +} + +class RubyAstNodeParent extends @ruby_ast_node_parent { + string toString() { none() } +} + +from RubyAstNode node, RubyAstNodeParent parent, int index, Location loc +where + ruby_ast_node_info(node, parent, index, loc) and + not node = any(ScopeResolutionMethodCall c).getScopeResolution() and + not parent = any(ScopeResolutionMethodCall c) and + not parent = any(ScopeResolutionMethodCall c).getScopeResolution() + or + ruby_ast_node_info(node, _, _, loc) and + parent instanceof ScopeResolutionMethodCall and + node = + rank[index + 1](RubyAstNode child, int x, int oldIndex | + exists(RubyAstNodeParent oldParent | + ruby_ast_node_info(child, oldParent, oldIndex, _) and + child != parent.(ScopeResolutionMethodCall).getScopeResolution() + | + oldParent = parent and x = 1 + or + oldParent = parent.(ScopeResolutionMethodCall).getScopeResolution() and x = 0 + ) + | + child order by x, oldIndex + ) +select node, parent, index, loc diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_block_parameters_child.ql b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_block_parameters_child.ql new file mode 100644 index 00000000000..9611d522db5 --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_block_parameters_child.ql @@ -0,0 +1,29 @@ +class RubyBlockParameters extends @ruby_block_parameters { + string toString() { none() } +} + +class RubyIdentifier extends @ruby_token_identifier { + string toString() { none() } +} + +predicate blockParametersLocals(RubyBlockParameters params, int index, RubyIdentifier local) { + local = + rank[index + 1](@ruby_token semi, int semiIndex, RubyIdentifier id, int idIndex | + ruby_tokeninfo(semi, _, ";") and + ruby_ast_node_info(semi, params, semiIndex, _) and + ruby_ast_node_info(id, params, idIndex, _) and + idIndex > semiIndex + | + id order by idIndex + ) +} + +class RubyBlockParameter extends @ruby_block_parameters_child_type { + string toString() { none() } +} + +from RubyBlockParameters ruby_block_parameters, int index, RubyBlockParameter param +where + ruby_block_parameters_child(ruby_block_parameters, index, param) and + not blockParametersLocals(ruby_block_parameters, _, param) +select ruby_block_parameters, index, param diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_block_parameters_locals.ql b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_block_parameters_locals.ql new file mode 100644 index 00000000000..cbe70adde55 --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_block_parameters_locals.ql @@ -0,0 +1,23 @@ +class RubyBlockParameters extends @ruby_block_parameters { + string toString() { none() } +} + +class RubyIdentifier extends @ruby_token_identifier { + string toString() { none() } +} + +predicate blockParametersLocals(RubyBlockParameters params, int index, RubyIdentifier local) { + local = + rank[index + 1](@ruby_token semi, int semiIndex, RubyIdentifier id, int idIndex | + ruby_tokeninfo(semi, _, ";") and + ruby_ast_node_info(semi, params, semiIndex, _) and + ruby_ast_node_info(id, params, idIndex, _) and + idIndex > semiIndex + | + id order by idIndex + ) +} + +from RubyBlockParameters ruby_block_parameters, int index, RubyIdentifier local +where blockParametersLocals(ruby_block_parameters, index, local) +select ruby_block_parameters, index, local diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_arguments.ql b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_arguments.ql new file mode 100644 index 00000000000..39f55a926af --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_arguments.ql @@ -0,0 +1,43 @@ +class RubyCallMethodType = @ruby_token_operator or @ruby_underscore_variable; + +class RubyArgumentList extends @ruby_argument_list { + string toString() { none() } +} + +abstract class RubyCall extends @ruby_ast_node { + string toString() { none() } + + abstract RubyArgumentList getArguments(); +} + +class NormalRubyCall extends RubyCall, @ruby_call { + NormalRubyCall() { ruby_call_def(this, any(RubyCallMethodType m)) } + + override RubyArgumentList getArguments() { ruby_call_arguments(this, result) } +} + +class ImplicitRubyCall extends RubyCall, @ruby_call { + RubyArgumentList arguments; + + ImplicitRubyCall() { ruby_call_def(this, arguments) } + + override RubyArgumentList getArguments() { result = arguments } +} + +class ScopeResolutionCall extends RubyCall, @ruby_scope_resolution { + ScopeResolutionCall() { + ruby_scope_resolution_def(this, any(@ruby_token_identifier m)) and + not ruby_call_def(_, this) + } + + override RubyArgumentList getArguments() { none() } +} + +class ScopeResolutionMethodCall extends RubyCall, @ruby_call { + ScopeResolutionMethodCall() { ruby_call_def(this, any(@ruby_scope_resolution s)) } + + override RubyArgumentList getArguments() { ruby_call_arguments(this, result) } +} + +from RubyCall ruby_call +select ruby_call, ruby_call.getArguments() diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_def.ql b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_def.ql new file mode 100644 index 00000000000..6e5babf86f2 --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_def.ql @@ -0,0 +1,27 @@ +class RubyCallMethodType = @ruby_token_operator or @ruby_underscore_variable; + +abstract class RubyCall extends @ruby_ast_node { + string toString() { none() } +} + +class NormalRubyCall extends RubyCall, @ruby_call { + NormalRubyCall() { ruby_call_def(this, any(RubyCallMethodType m)) } +} + +class ImplicitRubyCall extends RubyCall, @ruby_call { + ImplicitRubyCall() { ruby_call_def(this, any(@ruby_argument_list a)) } +} + +class ScopeResolutionCall extends RubyCall, @ruby_scope_resolution { + ScopeResolutionCall() { + ruby_scope_resolution_def(this, any(@ruby_token_identifier m)) and + not ruby_call_def(_, this) + } +} + +class ScopeResolutionMethodCall extends RubyCall, @ruby_call { + ScopeResolutionMethodCall() { ruby_call_def(this, any(@ruby_scope_resolution s)) } +} + +from RubyCall ruby_call +select ruby_call diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_method.ql b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_method.ql new file mode 100644 index 00000000000..200fad69b31 --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_method.ql @@ -0,0 +1,52 @@ +class RubyCallMethodType = @ruby_token_operator or @ruby_underscore_variable; + +class RubyMethod extends RubyCallMethodType { + string toString() { none() } +} + +abstract class RubyCall extends @ruby_ast_node { + string toString() { none() } + + abstract RubyMethod getMethod(); +} + +class NormalRubyCall extends RubyCall, @ruby_call { + private RubyMethod method; + + NormalRubyCall() { ruby_call_def(this, method) } + + override RubyMethod getMethod() { result = method } +} + +class ImplicitRubyCall extends RubyCall, @ruby_call { + ImplicitRubyCall() { ruby_call_def(this, any(@ruby_argument_list a)) } + + override RubyMethod getMethod() { none() } +} + +class ScopeResolutionCall extends RubyCall, @ruby_scope_resolution { + private @ruby_token_identifier method; + + ScopeResolutionCall() { + ruby_scope_resolution_def(this, method) and + not ruby_call_def(_, this) + } + + override RubyMethod getMethod() { result = method } +} + +class ScopeResolutionMethodCall extends RubyCall, @ruby_call { + private RubyMethod method; + + ScopeResolutionMethodCall() { + exists(@ruby_scope_resolution scope | + ruby_call_def(this, scope) and + ruby_scope_resolution_def(scope, method) + ) + } + + override RubyMethod getMethod() { result = method } +} + +from RubyCall ruby_call +select ruby_call, ruby_call.getMethod() diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_operator.ql b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_operator.ql new file mode 100644 index 00000000000..a8c2086529a --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_operator.ql @@ -0,0 +1,45 @@ +class RubyCallOperator extends @ruby_reserved_word { + RubyCallOperator() { ruby_tokeninfo(this, _, [".", "::", "&."]) } + + string toString() { none() } +} + +class RubyCallMethodType = @ruby_token_operator or @ruby_underscore_variable; + +abstract class RubyCall extends @ruby_ast_node { + string toString() { none() } + + abstract RubyCallOperator getOperator(); +} + +class NormalRubyCall extends RubyCall, @ruby_call { + NormalRubyCall() { ruby_call_def(this, any(RubyCallMethodType m)) } + + override RubyCallOperator getOperator() { ruby_ast_node_info(result, this, _, _) } +} + +class ImplicitRubyCall extends RubyCall, @ruby_call { + ImplicitRubyCall() { ruby_call_def(this, any(@ruby_argument_list a)) } + + override RubyCallOperator getOperator() { ruby_ast_node_info(result, this, _, _) } +} + +class ScopeResolutionCall extends RubyCall, @ruby_scope_resolution { + ScopeResolutionCall() { + ruby_scope_resolution_def(this, any(@ruby_token_identifier m)) and + not ruby_call_def(_, this) + } + + override RubyCallOperator getOperator() { ruby_ast_node_info(result, this, _, _) } +} + +class ScopeResolutionMethodCall extends RubyCall, @ruby_call { + private @ruby_scope_resolution scope; + + ScopeResolutionMethodCall() { ruby_call_def(this, scope) } + + override RubyCallOperator getOperator() { ruby_ast_node_info(result, scope, _, _) } +} + +from RubyCall ruby_call +select ruby_call, ruby_call.getOperator() diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_receiver.ql b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_receiver.ql new file mode 100644 index 00000000000..81a316eaabd --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_receiver.ql @@ -0,0 +1,43 @@ +class RubyCallMethodType = @ruby_token_operator or @ruby_underscore_variable; + +class RubyPrimary extends @ruby_underscore_primary { + string toString() { none() } +} + +abstract class RubyCall extends @ruby_ast_node { + string toString() { none() } + + abstract RubyPrimary getReceiver(); +} + +class NormalRubyCall extends RubyCall, @ruby_call { + NormalRubyCall() { ruby_call_def(this, any(RubyCallMethodType m)) } + + override RubyPrimary getReceiver() { ruby_call_receiver(this, result) } +} + +class ImplicitRubyCall extends RubyCall, @ruby_call { + ImplicitRubyCall() { ruby_call_def(this, any(@ruby_argument_list a)) } + + override RubyPrimary getReceiver() { ruby_call_receiver(this, result) } +} + +class ScopeResolutionCall extends RubyCall, @ruby_scope_resolution { + ScopeResolutionCall() { + ruby_scope_resolution_def(this, any(@ruby_token_identifier m)) and + not ruby_call_def(_, this) + } + + override RubyPrimary getReceiver() { ruby_scope_resolution_scope(this, result) } +} + +class ScopeResolutionMethodCall extends RubyCall, @ruby_call { + private @ruby_scope_resolution scope; + + ScopeResolutionMethodCall() { ruby_call_def(this, scope) } + + override RubyPrimary getReceiver() { ruby_scope_resolution_scope(scope, result) } +} + +from RubyCall ruby_call +select ruby_call, ruby_call.getReceiver() diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_scope_resolution_def.ql b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_scope_resolution_def.ql new file mode 100644 index 00000000000..db858388b65 --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_scope_resolution_def.ql @@ -0,0 +1,16 @@ +class RubyScopeResolution extends @ruby_scope_resolution { + RubyScopeResolution() { + exists(RubyConstant name | ruby_scope_resolution_def(this, name)) and + not ruby_call_def(_, this) + } + + string toString() { none() } +} + +class RubyConstant extends @ruby_token_constant { + string toString() { none() } +} + +from RubyScopeResolution scope, RubyConstant name +where ruby_scope_resolution_def(scope, name) +select scope, name diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_tokeninfo.ql b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_tokeninfo.ql new file mode 100644 index 00000000000..1d4af53f766 --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_tokeninfo.ql @@ -0,0 +1,20 @@ +private class RubyToken extends @ruby_token { + string toString() { none() } +} + +bindingset[old] +private int newKind(int old) { + // @ruby_token_complex was removed, for lack of a better solution + // it gets translated to @ruby_token_float + // 4 = @ruby_token_complex + // 10 = @ruby_token_float + old = 4 and result = 10 + or + old <= 3 and result = old + or + old >= 5 and result = old - 1 +} + +from RubyToken id, int kind, string value +where ruby_tokeninfo(id, kind, value) +select id, newKind(kind), value diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/upgrade.properties b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/upgrade.properties new file mode 100644 index 00000000000..8c5b2c86673 --- /dev/null +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/upgrade.properties @@ -0,0 +1,12 @@ +description: tree-sitter-ruby update +compatibility: backwards +ruby_block_parameters_child.rel: run ruby_block_parameters_child.qlo +ruby_block_parameters_locals.rel: run ruby_block_parameters_locals.qlo +ruby_call_def.rel: run ruby_call_def.qlo +ruby_call_arguments.rel: run ruby_call_arguments.qlo +ruby_call_method.rel: run ruby_call_method.qlo +ruby_call_operator.rel: run ruby_call_operator.qlo +ruby_call_receiver.rel: run ruby_call_receiver.qlo +ruby_scope_resolution_def.rel: run ruby_scope_resolution_def.qlo +ruby_ast_node_info.rel: run ruby_ast_node_info.qlo +ruby_tokeninfo.rel: run ruby_tokeninfo.qlo From cf4325c86f7f1fb8d0f4701c483b5dc84a10b6a2 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Fri, 29 Apr 2022 16:19:11 +0200 Subject: [PATCH 106/171] Add change note --- ruby/ql/lib/change-notes/2022-04-30-update-grammar.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ruby/ql/lib/change-notes/2022-04-30-update-grammar.md diff --git a/ruby/ql/lib/change-notes/2022-04-30-update-grammar.md b/ruby/ql/lib/change-notes/2022-04-30-update-grammar.md new file mode 100644 index 00000000000..34a485c94e6 --- /dev/null +++ b/ruby/ql/lib/change-notes/2022-04-30-update-grammar.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +The TreeSitter Ruby grammar has been updated; this fixes several issues where Ruby code was parsed incorrectly. From 714465bf39d97e31aa6f0a7aa01c57e16f3c3078 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 2 May 2022 11:29:00 +0200 Subject: [PATCH 107/171] Python: Refactor `SaxParserSetFeatureCall` Originally made by @erik-krogh in https://github.com/github/codeql/pull/8693/files#diff-9627c1fb9a1cc77fb93e6b7e31af1a4fa908f2a60362cfb34377d24debb97398 Could not be applied directly to this PR, since this PR deletes the file. --- .../lib/semmle/python/frameworks/Stdlib.qll | 38 ++++--------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 10eaa9dc3b6..bf2b01930d2 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3408,7 +3408,7 @@ private module StdlibPrivate { * * See https://docs.python.org/3.10/library/xml.sax.reader.html#xml.sax.xmlreader.XMLReader.setFeature */ - private class SaxParserSetFeatureCall extends DataFlow::MethodCallNode { + private class SaxParserSetFeatureCall extends API::CallNode, DataFlow::MethodCallNode { SaxParserSetFeatureCall() { this = API::moduleImport("xml") @@ -3421,27 +3421,9 @@ private module StdlibPrivate { // The keyword argument names does not match documentation. I checked (with Python // 3.9.5) that the names used here actually works. - DataFlow::Node getFeatureArg() { result in [this.getArg(0), this.getArgByName("name")] } + API::Node getFeatureArg() { result = this.getParameter(0, "name") } - DataFlow::Node getStateArg() { result in [this.getArg(1), this.getArgByName("state")] } - } - - /** Gets a back-reference to the `setFeature` state argument `arg`. */ - private DataFlow::TypeTrackingNode saxParserSetFeatureStateArgBacktracker( - DataFlow::TypeBackTracker t, DataFlow::Node arg - ) { - t.start() and - arg = any(SaxParserSetFeatureCall c).getStateArg() and - result = arg.getALocalSource() - or - exists(DataFlow::TypeBackTracker t2 | - result = saxParserSetFeatureStateArgBacktracker(t2, arg).backtrack(t2, t) - ) - } - - /** Gets a back-reference to the `setFeature` state argument `arg`. */ - DataFlow::LocalSourceNode saxParserSetFeatureStateArgBacktracker(DataFlow::Node arg) { - result = saxParserSetFeatureStateArgBacktracker(DataFlow::TypeBackTracker::end(), arg) + API::Node getStateArg() { result = this.getParameter(1, "state") } } /** @@ -3452,16 +3434,13 @@ private module StdlibPrivate { private DataFlow::Node saxParserWithFeatureExternalGesTurnedOn(DataFlow::TypeTracker t) { t.start() and exists(SaxParserSetFeatureCall call | - call.getFeatureArg() = + call.getFeatureArg().getARhs() = API::moduleImport("xml") .getMember("sax") .getMember("handler") .getMember("feature_external_ges") .getAUse() and - saxParserSetFeatureStateArgBacktracker(call.getStateArg()) - .asExpr() - .(BooleanLiteral) - .booleanValue() = true and + call.getStateArg().getAValueReachingRhs().asExpr().(BooleanLiteral).booleanValue() = true and result = call.getObject() ) or @@ -3471,16 +3450,13 @@ private module StdlibPrivate { // take account of that we can set the feature to False, which makes the parser safe again not exists(SaxParserSetFeatureCall call | call.getObject() = result and - call.getFeatureArg() = + call.getFeatureArg().getARhs() = API::moduleImport("xml") .getMember("sax") .getMember("handler") .getMember("feature_external_ges") .getAUse() and - saxParserSetFeatureStateArgBacktracker(call.getStateArg()) - .asExpr() - .(BooleanLiteral) - .booleanValue() = false + call.getStateArg().getAValueReachingRhs().asExpr().(BooleanLiteral).booleanValue() = false ) } From 8602a6f6c98f5a9f46db2c099ff7451b64f9b550 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 2 May 2022 15:38:28 +0200 Subject: [PATCH 108/171] Add models for OkHttp and Retrofit --- .../code/java/dataflow/ExternalFlow.qll | 2 + .../semmle/code/java/frameworks/OkHttp.qll | 55 ++ .../semmle/code/java/frameworks/Retrofit.qll | 12 + .../library-tests/frameworks/okhttp/Test.java | 237 ++++++++ .../library-tests/frameworks/okhttp/options | 1 + .../frameworks/okhttp/test.expected | 0 .../library-tests/frameworks/okhttp/test.ql | 6 + .../frameworks/retrofit/Test.java | 16 + .../library-tests/frameworks/retrofit/options | 1 + .../frameworks/retrofit/test.expected | 0 .../library-tests/frameworks/retrofit/test.ql | 6 + .../stubs/okhttp-4.9.3/kotlin/Function.java | 8 + .../test/stubs/okhttp-4.9.3/kotlin/Pair.java | 19 + .../test/stubs/okhttp-4.9.3/kotlin/Unit.java | 11 + .../collections/AbstractCollection.java | 26 + .../kotlin/collections/AbstractList.java | 40 ++ .../kotlin/jvm/functions/Function0.java | 10 + .../jvm/internal/markers/KMappedMarker.java | 8 + .../stubs/okhttp-4.9.3/okhttp3/Address.java | 84 +++ .../okhttp-4.9.3/okhttp3/Authenticator.java | 19 + .../stubs/okhttp-4.9.3/okhttp3/Cache.java | 137 +++++ .../okhttp-4.9.3/okhttp3/CacheControl.java | 78 +++ .../test/stubs/okhttp-4.9.3/okhttp3/Call.java | 24 + .../stubs/okhttp-4.9.3/okhttp3/Callback.java | 13 + .../okhttp3/CertificatePinner.java | 51 ++ .../stubs/okhttp-4.9.3/okhttp3/Challenge.java | 46 ++ .../okhttp-4.9.3/okhttp3/CipherSuite.java | 155 +++++ .../okhttp-4.9.3/okhttp3/Connection.java | 16 + .../okhttp-4.9.3/okhttp3/ConnectionPool.java | 17 + .../okhttp-4.9.3/okhttp3/ConnectionSpec.java | 58 ++ .../stubs/okhttp-4.9.3/okhttp3/Cookie.java | 93 +++ .../stubs/okhttp-4.9.3/okhttp3/CookieJar.java | 19 + .../okhttp-4.9.3/okhttp3/Dispatcher.java | 62 ++ .../test/stubs/okhttp-4.9.3/okhttp3/Dns.java | 17 + .../okhttp-4.9.3/okhttp3/EventListener.java | 60 ++ .../stubs/okhttp-4.9.3/okhttp3/Handshake.java | 78 +++ .../stubs/okhttp-4.9.3/okhttp3/Headers.java | 161 ++++++ .../stubs/okhttp-4.9.3/okhttp3/HttpUrl.java | 390 +++++++++++++ .../okhttp-4.9.3/okhttp3/Interceptor.java | 34 ++ .../stubs/okhttp-4.9.3/okhttp3/MediaType.java | 63 +++ .../okhttp-4.9.3/okhttp3/OkHttpClient.java | 528 ++++++++++++++++++ .../stubs/okhttp-4.9.3/okhttp3/Protocol.java | 18 + .../stubs/okhttp-4.9.3/okhttp3/Request.java | 182 ++++++ .../okhttp-4.9.3/okhttp3/RequestBody.java | 49 ++ .../stubs/okhttp-4.9.3/okhttp3/Response.java | 270 +++++++++ .../okhttp-4.9.3/okhttp3/ResponseBody.java | 45 ++ .../stubs/okhttp-4.9.3/okhttp3/Route.java | 41 ++ .../okhttp-4.9.3/okhttp3/TlsVersion.java | 28 + .../stubs/okhttp-4.9.3/okhttp3/WebSocket.java | 21 + .../okhttp3/WebSocketListener.java | 18 + .../okhttp3/internal/cache/CacheRequest.java | 11 + .../okhttp3/internal/cache/CacheStrategy.java | 20 + .../okhttp3/internal/cache/DiskLruCache.java | 106 ++++ .../okhttp3/internal/concurrent/Task.java | 20 + .../internal/concurrent/TaskQueue.java | 35 ++ .../internal/concurrent/TaskRunner.java | 35 ++ .../okhttp3/internal/connection/Exchange.java | 44 ++ .../internal/connection/ExchangeFinder.java | 24 + .../okhttp3/internal/connection/RealCall.java | 63 +++ .../internal/connection/RealConnection.java | 65 +++ .../connection/RealConnectionPool.java | 31 + .../internal/connection/RouteDatabase.java | 13 + .../okhttp3/internal/http/ExchangeCodec.java | 31 + .../internal/http/RealInterceptorChain.java | 36 ++ .../okhttp3/internal/http2/ErrorCode.java | 17 + .../okhttp3/internal/http2/Header.java | 38 ++ .../okhttp3/internal/http2/Hpack.java | 34 ++ .../internal/http2/Http2Connection.java | 153 +++++ .../okhttp3/internal/http2/Http2Reader.java | 42 ++ .../okhttp3/internal/http2/Http2Stream.java | 104 ++++ .../okhttp3/internal/http2/Http2Writer.java | 39 ++ .../okhttp3/internal/http2/PushObserver.java | 22 + .../okhttp3/internal/http2/Settings.java | 34 ++ .../okhttp3/internal/io/FileSystem.java | 25 + .../internal/tls/CertificateChainCleaner.java | 21 + .../okhttp3/internal/ws/RealWebSocket.java | 66 +++ .../internal/ws/WebSocketExtensions.java | 34 ++ .../okhttp3/internal/ws/WebSocketReader.java | 24 + .../stubs/okhttp-4.9.3/okio/AsyncTimeout.java | 28 + .../test/stubs/okhttp-4.9.3/okio/Buffer.java | 469 ++++++++++++++++ .../stubs/okhttp-4.9.3/okio/BufferedSink.java | 41 ++ .../okhttp-4.9.3/okio/BufferedSource.java | 60 ++ .../stubs/okhttp-4.9.3/okio/ByteString.java | 284 ++++++++++ .../test/stubs/okhttp-4.9.3/okio/Options.java | 28 + .../test/stubs/okhttp-4.9.3/okio/Segment.java | 31 + .../ql/test/stubs/okhttp-4.9.3/okio/Sink.java | 16 + .../test/stubs/okhttp-4.9.3/okio/Source.java | 14 + .../test/stubs/okhttp-4.9.3/okio/Timeout.java | 30 + .../stubs/retrofit-2.9.0/kotlin/Function.java | 8 + .../stubs/retrofit-2.9.0/kotlin/Pair.java | 19 + .../stubs/retrofit-2.9.0/kotlin/Unit.java | 11 + .../collections/AbstractCollection.java | 26 + .../kotlin/collections/AbstractList.java | 40 ++ .../kotlin/collections/IntIterator.java | 14 + .../kotlin/jvm/functions/Function0.java | 10 + .../kotlin/jvm/functions/Function1.java | 10 + .../jvm/internal/markers/KMappedMarker.java | 8 + .../kotlin/ranges/ClosedRange.java | 12 + .../kotlin/ranges/IntProgression.java | 26 + .../kotlin/ranges/IntRange.java | 26 + .../kotlin/sequences/Sequence.java | 10 + .../retrofit-2.9.0/kotlin/text/FlagEnum.java | 10 + .../kotlin/text/MatchGroup.java | 19 + .../kotlin/text/MatchGroupCollection.java | 12 + .../kotlin/text/MatchResult.java | 24 + .../retrofit-2.9.0/kotlin/text/Regex.java | 42 ++ .../kotlin/text/RegexOption.java | 12 + .../stubs/retrofit-2.9.0/retrofit2/Call.java | 20 + .../retrofit-2.9.0/retrofit2/CallAdapter.java | 22 + .../retrofit-2.9.0/retrofit2/Callback.java | 12 + .../retrofit-2.9.0/retrofit2/Converter.java | 24 + .../retrofit-2.9.0/retrofit2/Response.java | 25 + .../retrofit-2.9.0/retrofit2/Retrofit.java | 51 ++ 113 files changed, 6014 insertions(+) create mode 100644 java/ql/lib/semmle/code/java/frameworks/OkHttp.qll create mode 100644 java/ql/lib/semmle/code/java/frameworks/Retrofit.qll create mode 100644 java/ql/test/library-tests/frameworks/okhttp/Test.java create mode 100644 java/ql/test/library-tests/frameworks/okhttp/options create mode 100644 java/ql/test/library-tests/frameworks/okhttp/test.expected create mode 100644 java/ql/test/library-tests/frameworks/okhttp/test.ql create mode 100644 java/ql/test/library-tests/frameworks/retrofit/Test.java create mode 100644 java/ql/test/library-tests/frameworks/retrofit/options create mode 100644 java/ql/test/library-tests/frameworks/retrofit/test.expected create mode 100644 java/ql/test/library-tests/frameworks/retrofit/test.ql create mode 100644 java/ql/test/stubs/okhttp-4.9.3/kotlin/Function.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/kotlin/Pair.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/kotlin/Unit.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/kotlin/collections/AbstractCollection.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/kotlin/collections/AbstractList.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/kotlin/jvm/functions/Function0.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/kotlin/jvm/internal/markers/KMappedMarker.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Address.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Authenticator.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Cache.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/CacheControl.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Call.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Callback.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/CertificatePinner.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Challenge.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/CipherSuite.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Connection.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/ConnectionPool.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/ConnectionSpec.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Cookie.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/CookieJar.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Dispatcher.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Dns.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/EventListener.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Handshake.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Headers.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/HttpUrl.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Interceptor.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/MediaType.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/OkHttpClient.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Protocol.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Request.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/RequestBody.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Response.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/ResponseBody.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/Route.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/TlsVersion.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/WebSocket.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/WebSocketListener.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/CacheRequest.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/CacheStrategy.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/DiskLruCache.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/Task.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/TaskQueue.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/TaskRunner.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/Exchange.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/ExchangeFinder.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealCall.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealConnection.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealConnectionPool.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RouteDatabase.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http/ExchangeCodec.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http/RealInterceptorChain.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/ErrorCode.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Header.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Hpack.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Connection.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Reader.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Stream.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Writer.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/PushObserver.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Settings.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/io/FileSystem.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/tls/CertificateChainCleaner.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/RealWebSocket.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/WebSocketExtensions.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/WebSocketReader.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okio/AsyncTimeout.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okio/Buffer.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okio/BufferedSink.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okio/BufferedSource.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okio/ByteString.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okio/Options.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okio/Segment.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okio/Sink.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okio/Source.java create mode 100644 java/ql/test/stubs/okhttp-4.9.3/okio/Timeout.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/Function.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/Pair.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/Unit.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/AbstractCollection.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/AbstractList.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/IntIterator.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/functions/Function0.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/functions/Function1.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/internal/markers/KMappedMarker.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/ClosedRange.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/IntProgression.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/IntRange.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/sequences/Sequence.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/text/FlagEnum.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchGroup.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchGroupCollection.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchResult.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/text/Regex.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/kotlin/text/RegexOption.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/retrofit2/Call.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/retrofit2/CallAdapter.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/retrofit2/Callback.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/retrofit2/Converter.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/retrofit2/Response.java create mode 100644 java/ql/test/stubs/retrofit-2.9.0/retrofit2/Retrofit.java diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index f3ac4a041b6..f3101c208db 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -102,8 +102,10 @@ private module Frameworks { private import semmle.code.java.frameworks.JsonJava private import semmle.code.java.frameworks.Logging private import semmle.code.java.frameworks.Objects + private import semmle.code.java.frameworks.OkHttp private import semmle.code.java.frameworks.Optional private import semmle.code.java.frameworks.Regex + private import semmle.code.java.frameworks.Retrofit private import semmle.code.java.frameworks.Stream private import semmle.code.java.frameworks.Strings private import semmle.code.java.frameworks.ratpack.Ratpack diff --git a/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll b/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll new file mode 100644 index 00000000000..36e23d45881 --- /dev/null +++ b/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll @@ -0,0 +1,55 @@ +/** + * Provides classes and predicates for working with the OkHttp client. + */ + +import java +import semmle.code.java.dataflow.ExternalFlow + +private class OkHttpOpenUrlSinks extends SinkModelCsv { + override predicate row(string row) { + row = + [ + "okhttp3;Request;true;Request;;;Argument[0];open-url", + "okhttp3;Request$Builder;true;url;;;Argument[0];open-url" + ] + } +} + +private class OKHttpSummaries extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "okhttp3;HttpUrl;false;parse;;;Argument[0];ReturnValue;taint", + "okhttp3;HttpUrl;false;uri;;;Argument[-1];ReturnValue;taint", + "okhttp3;HttpUrl;false;url;;;Argument[-1];ReturnValue;taint", + "okhttp3;HttpUrl$Builder;false;addEncodedPathSegment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;addEncodedPathSegments;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;addEncodedQueryParameter;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;addPathSegment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;addPathSegments;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;addQueryParameter;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;build;;;Argument[-1];ReturnValue;taint", + "okhttp3;HttpUrl$Builder;false;encodedFragment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;encodedPassword;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;encodedPath;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;encodedQuery;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;encodedUsername;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;fragment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;fragment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;host;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;password;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;port;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;query;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;removeAllEncodedQueryParameters;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;removeAllQueryParameters;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;removePathSegment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;scheme;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;scheme;;;Argument[0];Argument[-1];taint", + "okhttp3;HttpUrl$Builder;false;setEncodedPathSegment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;setEncodedQueryParameter;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;setPathSegment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;setQueryParameter;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;username;;;Argument[-1];ReturnValue;value", + ] + } +} diff --git a/java/ql/lib/semmle/code/java/frameworks/Retrofit.qll b/java/ql/lib/semmle/code/java/frameworks/Retrofit.qll new file mode 100644 index 00000000000..cb1aaa87667 --- /dev/null +++ b/java/ql/lib/semmle/code/java/frameworks/Retrofit.qll @@ -0,0 +1,12 @@ +/** + * Provides classes and predicates for working with the Retrofit API client. + */ + +import java +import semmle.code.java.dataflow.ExternalFlow + +private class RetrofitOpenUrlSinks extends SinkModelCsv { + override predicate row(string row) { + row = "retrofit2;Retrofit$Builder;true;baseUrl;;;Argument[0];open-url" + } +} diff --git a/java/ql/test/library-tests/frameworks/okhttp/Test.java b/java/ql/test/library-tests/frameworks/okhttp/Test.java new file mode 100644 index 00000000000..02950ccaa30 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/okhttp/Test.java @@ -0,0 +1,237 @@ +package generatedtest; + +import java.net.URI; +import java.net.URL; +import okhttp3.HttpUrl; +import okhttp3.Request; + +// Test case generated by GenerateFlowTestCase.ql +public class Test { + + Object source() { + return null; + } + + void sink(Object o) {} + + public void testSinks() { + new Request((HttpUrl) source(), null, null, null, null); // $ hasValueFlow + new Request.Builder().url((String) source()); // $ hasValueFlow + } + + public void test() throws Exception { + + { + // "okhttp3;HttpUrl$Builder;false;addEncodedPathSegment;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.addEncodedPathSegment(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;addEncodedPathSegments;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.addEncodedPathSegments(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;addEncodedQueryParameter;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.addEncodedQueryParameter(null, null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;addPathSegment;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.addPathSegment(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;addPathSegments;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.addPathSegments(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;addQueryParameter;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.addQueryParameter(null, null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;build;;;Argument[-1];ReturnValue;taint" + HttpUrl out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.build(); + sink(out); // $ hasTaintFlow + } + { + // "okhttp3;HttpUrl$Builder;false;encodedFragment;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.encodedFragment(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;encodedPassword;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.encodedPassword(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;encodedPath;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.encodedPath(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;encodedQuery;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.encodedQuery(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;encodedUsername;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.encodedUsername(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;fragment;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.fragment(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;host;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.host(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;password;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.password(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;port;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.port(0); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;query;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.query(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;removeAllEncodedQueryParameters;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.removeAllEncodedQueryParameters(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;removeAllQueryParameters;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.removeAllQueryParameters(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;removePathSegment;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.removePathSegment(0); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;scheme;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.scheme(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;scheme;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.scheme(in); + sink(out); // $ hasTaintFlow + } + { + // "okhttp3;HttpUrl$Builder;false;setEncodedPathSegment;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.setEncodedPathSegment(0, null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;setEncodedQueryParameter;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.setEncodedQueryParameter(null, null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;setPathSegment;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.setPathSegment(0, null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;setQueryParameter;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.setQueryParameter(null, null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl$Builder;false;username;;;Argument[-1];ReturnValue;value" + HttpUrl.Builder out = null; + HttpUrl.Builder in = (HttpUrl.Builder) source(); + out = in.username(null); + sink(out); // $ hasValueFlow + } + { + // "okhttp3;HttpUrl;false;parse;;;Argument[0];ReturnValue;taint" + HttpUrl out = null; + String in = (String) source(); + out = HttpUrl.parse(in); + sink(out); // $ hasTaintFlow + } + { + // "okhttp3;HttpUrl;false;uri;;;Argument[-1];ReturnValue;taint" + URI out = null; + HttpUrl in = (HttpUrl) source(); + out = in.uri(); + sink(out); // $ hasTaintFlow + } + { + // "okhttp3;HttpUrl;false;url;;;Argument[-1];ReturnValue;taint" + URL out = null; + HttpUrl in = (HttpUrl) source(); + out = in.url(); + sink(out); // $ hasTaintFlow + } + + } + +} diff --git a/java/ql/test/library-tests/frameworks/okhttp/options b/java/ql/test/library-tests/frameworks/okhttp/options new file mode 100644 index 00000000000..597cc3181f0 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/okhttp/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/okhttp-4.9.3 diff --git a/java/ql/test/library-tests/frameworks/okhttp/test.expected b/java/ql/test/library-tests/frameworks/okhttp/test.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/library-tests/frameworks/okhttp/test.ql b/java/ql/test/library-tests/frameworks/okhttp/test.ql new file mode 100644 index 00000000000..e78af7d25bf --- /dev/null +++ b/java/ql/test/library-tests/frameworks/okhttp/test.ql @@ -0,0 +1,6 @@ +import java +import TestUtilities.InlineFlowTest + +class FlowConf extends DefaultValueFlowConf { + override predicate isSink(DataFlow::Node n) { super.isSink(n) or sinkNode(n, "open-url") } +} diff --git a/java/ql/test/library-tests/frameworks/retrofit/Test.java b/java/ql/test/library-tests/frameworks/retrofit/Test.java new file mode 100644 index 00000000000..a5513298230 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/retrofit/Test.java @@ -0,0 +1,16 @@ +import java.net.URL; +import okhttp3.HttpUrl; +import retrofit2.Retrofit; + +public class Test { + public Object source() { + return null; + } + + public void test() { + Retrofit.Builder builder = new Retrofit.Builder(); + builder.baseUrl((String) source()); // $ hasValueFlow + builder.baseUrl((URL) source()); // $ hasValueFlow + builder.baseUrl((HttpUrl) source()); // $ hasValueFlow + } +} diff --git a/java/ql/test/library-tests/frameworks/retrofit/options b/java/ql/test/library-tests/frameworks/retrofit/options new file mode 100644 index 00000000000..87371f0fe2a --- /dev/null +++ b/java/ql/test/library-tests/frameworks/retrofit/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/okhttp-4.9.3:${testdir}/../../../stubs/retrofit-2.9.0 diff --git a/java/ql/test/library-tests/frameworks/retrofit/test.expected b/java/ql/test/library-tests/frameworks/retrofit/test.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/library-tests/frameworks/retrofit/test.ql b/java/ql/test/library-tests/frameworks/retrofit/test.ql new file mode 100644 index 00000000000..e78af7d25bf --- /dev/null +++ b/java/ql/test/library-tests/frameworks/retrofit/test.ql @@ -0,0 +1,6 @@ +import java +import TestUtilities.InlineFlowTest + +class FlowConf extends DefaultValueFlowConf { + override predicate isSink(DataFlow::Node n) { super.isSink(n) or sinkNode(n, "open-url") } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/kotlin/Function.java b/java/ql/test/stubs/okhttp-4.9.3/kotlin/Function.java new file mode 100644 index 00000000000..ec16743fa7a --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/kotlin/Function.java @@ -0,0 +1,8 @@ +// Generated automatically from kotlin.Function for testing purposes + +package kotlin; + + +public interface Function +{ +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/kotlin/Pair.java b/java/ql/test/stubs/okhttp-4.9.3/kotlin/Pair.java new file mode 100644 index 00000000000..74869657cb4 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/kotlin/Pair.java @@ -0,0 +1,19 @@ +// Generated automatically from kotlin.Pair for testing purposes + +package kotlin; + +import java.io.Serializable; + +public class Pair implements Serializable +{ + protected Pair() {} + public Pair(A p0, B p1){} + public String toString(){ return null; } + public boolean equals(Object p0){ return false; } + public final A component1(){ return null; } + public final A getFirst(){ return null; } + public final B component2(){ return null; } + public final B getSecond(){ return null; } + public final Pair copy(A p0, B p1){ return null; } + public int hashCode(){ return 0; } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/kotlin/Unit.java b/java/ql/test/stubs/okhttp-4.9.3/kotlin/Unit.java new file mode 100644 index 00000000000..c2aeb7e3616 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/kotlin/Unit.java @@ -0,0 +1,11 @@ +// Generated automatically from kotlin.Unit for testing purposes + +package kotlin; + + +public class Unit +{ + protected Unit() {} + public String toString(){ return null; } + public static Unit INSTANCE = null; +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/kotlin/collections/AbstractCollection.java b/java/ql/test/stubs/okhttp-4.9.3/kotlin/collections/AbstractCollection.java new file mode 100644 index 00000000000..48555f6818e --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/kotlin/collections/AbstractCollection.java @@ -0,0 +1,26 @@ +// Generated automatically from kotlin.collections.AbstractCollection for testing purposes + +package kotlin.collections; + +import java.util.Collection; +import java.util.Iterator; +import kotlin.jvm.internal.markers.KMappedMarker; + +abstract public class AbstractCollection implements Collection, KMappedMarker +{ + protected AbstractCollection(){} + public T[] toArray(T[] p0){ return null; } + public Object[] toArray(){ return null; } + public String toString(){ return null; } + public abstract Iterator iterator(); + public abstract int getSize(); + public boolean add(E p0){ return false; } + public boolean addAll(Collection p0){ return false; } + public boolean contains(Object p0){ return false; } + public boolean containsAll(Collection p0){ return false; } + public boolean isEmpty(){ return false; } + public boolean remove(Object p0){ return false; } + public boolean removeAll(Collection p0){ return false; } + public boolean retainAll(Collection p0){ return false; } + public void clear(){} +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/kotlin/collections/AbstractList.java b/java/ql/test/stubs/okhttp-4.9.3/kotlin/collections/AbstractList.java new file mode 100644 index 00000000000..1a11dbf9132 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/kotlin/collections/AbstractList.java @@ -0,0 +1,40 @@ +// Generated automatically from kotlin.collections.AbstractList for testing purposes + +package kotlin.collections; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import kotlin.collections.AbstractCollection; +import kotlin.jvm.internal.markers.KMappedMarker; + +abstract public class AbstractList extends AbstractCollection implements KMappedMarker, List +{ + protected AbstractList(){} + public E remove(int p0){ return null; } + public E set(int p0, E p1){ return null; } + public Iterator iterator(){ return null; } + public List subList(int p0, int p1){ return null; } + public ListIterator listIterator(){ return null; } + public ListIterator listIterator(int p0){ return null; } + public abstract E get(int p0); + public abstract int getSize(); + public boolean addAll(int p0, Collection p1){ return false; } + public boolean equals(Object p0){ return false; } + public int hashCode(){ return 0; } + public int indexOf(Object p0){ return 0; } + public int lastIndexOf(Object p0){ return 0; } + public static AbstractList.Companion Companion = null; + public void add(int p0, E p1){} + static public class Companion + { + protected Companion() {} + public final boolean orderedEquals$kotlin_stdlib(Collection p0, Collection p1){ return false; } + public final int orderedHashCode$kotlin_stdlib(Collection p0){ return 0; } + public final void checkBoundsIndexes$kotlin_stdlib(int p0, int p1, int p2){} + public final void checkElementIndex$kotlin_stdlib(int p0, int p1){} + public final void checkPositionIndex$kotlin_stdlib(int p0, int p1){} + public final void checkRangeIndexes$kotlin_stdlib(int p0, int p1, int p2){} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/kotlin/jvm/functions/Function0.java b/java/ql/test/stubs/okhttp-4.9.3/kotlin/jvm/functions/Function0.java new file mode 100644 index 00000000000..93c5085ec5f --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/kotlin/jvm/functions/Function0.java @@ -0,0 +1,10 @@ +// Generated automatically from kotlin.jvm.functions.Function0 for testing purposes + +package kotlin.jvm.functions; + +import kotlin.Function; + +public interface Function0 extends Function +{ + R invoke(); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/kotlin/jvm/internal/markers/KMappedMarker.java b/java/ql/test/stubs/okhttp-4.9.3/kotlin/jvm/internal/markers/KMappedMarker.java new file mode 100644 index 00000000000..08178fd7cc5 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/kotlin/jvm/internal/markers/KMappedMarker.java @@ -0,0 +1,8 @@ +// Generated automatically from kotlin.jvm.internal.markers.KMappedMarker for testing purposes + +package kotlin.jvm.internal.markers; + + +public interface KMappedMarker +{ +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Address.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Address.java new file mode 100644 index 00000000000..aa50e384773 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Address.java @@ -0,0 +1,84 @@ +// Generated automatically from okhttp3.Address for testing purposes + +package okhttp3; + +import java.net.Proxy; +import java.net.ProxySelector; +import java.util.List; +import javax.net.SocketFactory; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSocketFactory; +import okhttp3.Authenticator; +import okhttp3.CertificatePinner; +import okhttp3.ConnectionSpec; +import okhttp3.Dns; +import okhttp3.HttpUrl; +import okhttp3.Protocol; + +public class Address { + protected Address() {} + + public Address(String p0, int p1, Dns p2, SocketFactory p3, SSLSocketFactory p4, + HostnameVerifier p5, CertificatePinner p6, Authenticator p7, Proxy p8, + List p9, List p10, ProxySelector p11) {} + + public String toString() { + return null; + } + + public boolean equals(Object p0) { + return false; + } + + public final Authenticator proxyAuthenticator() { + return null; + } + + public final CertificatePinner certificatePinner() { + return null; + } + + public final Dns dns() { + return null; + } + + public final HostnameVerifier hostnameVerifier() { + return null; + } + + public final HttpUrl url() { + return null; + } + + public final List connectionSpecs() { + return null; + } + + public final List protocols() { + return null; + } + + public final Proxy proxy() { + return null; + } + + public final ProxySelector proxySelector() { + return null; + } + + public final SSLSocketFactory sslSocketFactory() { + return null; + } + + public final SocketFactory socketFactory() { + return null; + } + + public final boolean equalsNonHost$okhttp(Address p0) { + return false; + } + + public int hashCode() { + return 0; + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Authenticator.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Authenticator.java new file mode 100644 index 00000000000..2b969cbc064 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Authenticator.java @@ -0,0 +1,19 @@ +// Generated automatically from okhttp3.Authenticator for testing purposes + +package okhttp3; + +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.Route; + +public interface Authenticator +{ + Request authenticate(Route p0, Response p1); + static Authenticator JAVA_NET_AUTHENTICATOR = null; + static Authenticator NONE = null; + static Authenticator.Companion Companion = null; + static public class Companion + { + protected Companion() {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Cache.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Cache.java new file mode 100644 index 00000000000..789ff82e4f8 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Cache.java @@ -0,0 +1,137 @@ +// Generated automatically from okhttp3.Cache for testing purposes + +package okhttp3; + +import java.io.Closeable; +import java.io.File; +import java.io.Flushable; +import java.util.Iterator; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.internal.cache.CacheRequest; +import okhttp3.internal.cache.CacheStrategy; +import okhttp3.internal.cache.DiskLruCache; +import okhttp3.internal.io.FileSystem; +import okio.BufferedSource; + +public class Cache implements Closeable, Flushable { + protected Cache() {} + + public Cache(File p0, long p1) {} + + public Cache(File p0, long p1, FileSystem p2) {} + + public final CacheRequest put$okhttp(Response p0) { + return null; + } + + public final DiskLruCache getCache$okhttp() { + return null; + } + + public final File directory() { + return null; + } + + public final Iterator urls() { + return null; + } + + public final Response get$okhttp(Request p0) { + return null; + } + + public final boolean isClosed() { + return false; + } + + public final int getWriteAbortCount$okhttp() { + return 0; + } + + public final int getWriteSuccessCount$okhttp() { + return 0; + } + + public final int hitCount() { + return 0; + } + + public final int networkCount() { + return 0; + } + + public final int requestCount() { + return 0; + } + + public final int writeAbortCount() { + return 0; + } + + public final int writeSuccessCount() { + return 0; + } + + public final long maxSize() { + return 0; + } + + public final long size() { + return 0; + } + + public final void delete() {} + + public final void evictAll() {} + + public final void initialize() {} + + public final void remove$okhttp(Request p0) {} + + public final void setWriteAbortCount$okhttp(int p0) {} + + public final void setWriteSuccessCount$okhttp(int p0) {} + + public final void trackConditionalCacheHit$okhttp() {} + + public final void trackResponse$okhttp(CacheStrategy p0) {} + + public final void update$okhttp(Response p0, Response p1) {} + + public static Cache.Companion Companion = null; + + public static String key(HttpUrl p0) { + return null; + } + + public void close() {} + + public void flush() {} + + static public class Companion { + protected Companion() {} + + public final Headers varyHeaders(Response p0) { + return null; + } + + public final String key(HttpUrl p0) { + return null; + } + + public final boolean hasVaryAll(Response p0) { + return false; + } + + public final boolean varyMatches(Response p0, Headers p1, Request p2) { + return false; + } + + public final int readInt$okhttp(BufferedSource p0) { + return 0; + } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CacheControl.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CacheControl.java new file mode 100644 index 00000000000..564f1cad733 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CacheControl.java @@ -0,0 +1,78 @@ +// Generated automatically from okhttp3.CacheControl for testing purposes + +package okhttp3; + +import okhttp3.Headers; + +public class CacheControl { + protected CacheControl() {} + + public String toString() { + return null; + } + + public final boolean immutable() { + return false; + } + + public final boolean isPrivate() { + return false; + } + + public final boolean isPublic() { + return false; + } + + public final boolean mustRevalidate() { + return false; + } + + public final boolean noCache() { + return false; + } + + public final boolean noStore() { + return false; + } + + public final boolean noTransform() { + return false; + } + + public final boolean onlyIfCached() { + return false; + } + + public final int maxAgeSeconds() { + return 0; + } + + public final int maxStaleSeconds() { + return 0; + } + + public final int minFreshSeconds() { + return 0; + } + + public final int sMaxAgeSeconds() { + return 0; + } + + public static CacheControl FORCE_CACHE = null; + public static CacheControl FORCE_NETWORK = null; + + public static CacheControl parse(Headers p0) { + return null; + } + + public static CacheControl.Companion Companion = null; + + static public class Companion { + protected Companion() {} + + public final CacheControl parse(Headers p0) { + return null; + } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Call.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Call.java new file mode 100644 index 00000000000..69017719bb9 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Call.java @@ -0,0 +1,24 @@ +// Generated automatically from okhttp3.Call for testing purposes + +package okhttp3; + +import okhttp3.Callback; +import okhttp3.Request; +import okhttp3.Response; +import okio.Timeout; + +public interface Call extends Cloneable +{ + Call clone(); + Request request(); + Response execute(); + Timeout timeout(); + boolean isCanceled(); + boolean isExecuted(); + static public interface Factory + { + Call newCall(Request p0); + } + void cancel(); + void enqueue(Callback p0); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Callback.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Callback.java new file mode 100644 index 00000000000..e86c6d20801 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Callback.java @@ -0,0 +1,13 @@ +// Generated automatically from okhttp3.Callback for testing purposes + +package okhttp3; + +import java.io.IOException; +import okhttp3.Call; +import okhttp3.Response; + +public interface Callback +{ + void onFailure(Call p0, IOException p1); + void onResponse(Call p0, Response p1); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CertificatePinner.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CertificatePinner.java new file mode 100644 index 00000000000..15e83d72f46 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CertificatePinner.java @@ -0,0 +1,51 @@ +// Generated automatically from okhttp3.CertificatePinner for testing purposes + +package okhttp3; + +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.Set; +import kotlin.jvm.functions.Function0; +import okhttp3.internal.tls.CertificateChainCleaner; +import okio.ByteString; + +public class CertificatePinner +{ + protected CertificatePinner() {} + public CertificatePinner(Set p0, CertificateChainCleaner p1){} + public boolean equals(Object p0){ return false; } + public final CertificateChainCleaner getCertificateChainCleaner$okhttp(){ return null; } + public final CertificatePinner withCertificateChainCleaner$okhttp(CertificateChainCleaner p0){ return null; } + public final List findMatchingPins(String p0){ return null; } + public final Set getPins(){ return null; } + public final void check$okhttp(String p0, Function0> p1){} + public final void check(String p0, Certificate... p1){} + public final void check(String p0, List p1){} + public int hashCode(){ return 0; } + public static ByteString sha1Hash(X509Certificate p0){ return null; } + public static ByteString sha256Hash(X509Certificate p0){ return null; } + public static CertificatePinner DEFAULT = null; + public static CertificatePinner.Companion Companion = null; + public static String pin(Certificate p0){ return null; } + static public class Companion + { + protected Companion() {} + public final ByteString sha1Hash(X509Certificate p0){ return null; } + public final ByteString sha256Hash(X509Certificate p0){ return null; } + public final String pin(Certificate p0){ return null; } + } + static public class Pin + { + protected Pin() {} + public Pin(String p0, String p1){} + public String toString(){ return null; } + public boolean equals(Object p0){ return false; } + public final ByteString getHash(){ return null; } + public final String getHashAlgorithm(){ return null; } + public final String getPattern(){ return null; } + public final boolean matchesCertificate(X509Certificate p0){ return false; } + public final boolean matchesHostname(String p0){ return false; } + public int hashCode(){ return 0; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Challenge.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Challenge.java new file mode 100644 index 00000000000..f64fe1436b4 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Challenge.java @@ -0,0 +1,46 @@ +// Generated automatically from okhttp3.Challenge for testing purposes + +package okhttp3; + +import java.nio.charset.Charset; +import java.util.Map; + +public class Challenge { + protected Challenge() {} + + public Challenge(String p0, Map p1) {} + + public Challenge(String p0, String p1) {} + + public String toString() { + return null; + } + + public boolean equals(Object p0) { + return false; + } + + public final Challenge withCharset(Charset p0) { + return null; + } + + public final Charset charset() { + return null; + } + + public final Map authParams() { + return null; + } + + public final String realm() { + return null; + } + + public final String scheme() { + return null; + } + + public int hashCode() { + return 0; + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CipherSuite.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CipherSuite.java new file mode 100644 index 00000000000..24d10e5da04 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CipherSuite.java @@ -0,0 +1,155 @@ +// Generated automatically from okhttp3.CipherSuite for testing purposes + +package okhttp3; + +import java.util.Comparator; + +public class CipherSuite { + protected CipherSuite() {} + + public String toString() { + return null; + } + + public final String javaName() { + return null; + } + + public static CipherSuite TLS_AES_128_CCM_8_SHA256 = null; + public static CipherSuite TLS_AES_128_CCM_SHA256 = null; + public static CipherSuite TLS_AES_128_GCM_SHA256 = null; + public static CipherSuite TLS_AES_256_GCM_SHA384 = null; + public static CipherSuite TLS_CHACHA20_POLY1305_SHA256 = null; + public static CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = null; + public static CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = null; + public static CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA = null; + public static CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = null; + public static CipherSuite TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = null; + public static CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA = null; + public static CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = null; + public static CipherSuite TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = null; + public static CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = null; + public static CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = null; + public static CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = null; + public static CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = null; + public static CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = null; + public static CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA = null; + public static CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = null; + public static CipherSuite TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = null; + public static CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA = null; + public static CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = null; + public static CipherSuite TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = null; + public static CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = null; + public static CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = null; + public static CipherSuite TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = null; + public static CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = null; + public static CipherSuite TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = null; + public static CipherSuite TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = null; + public static CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = null; + public static CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA = null; + public static CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA256 = null; + public static CipherSuite TLS_DH_anon_WITH_AES_128_GCM_SHA256 = null; + public static CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA = null; + public static CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA256 = null; + public static CipherSuite TLS_DH_anon_WITH_AES_256_GCM_SHA384 = null; + public static CipherSuite TLS_DH_anon_WITH_DES_CBC_SHA = null; + public static CipherSuite TLS_DH_anon_WITH_RC4_128_MD5 = null; + public static CipherSuite TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = null; + public static CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = null; + public static CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = null; + public static CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = null; + public static CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = null; + public static CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = null; + public static CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = null; + public static CipherSuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = null; + public static CipherSuite TLS_ECDHE_ECDSA_WITH_NULL_SHA = null; + public static CipherSuite TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = null; + public static CipherSuite TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = null; + public static CipherSuite TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = null; + public static CipherSuite TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = null; + public static CipherSuite TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = null; + public static CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = null; + public static CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = null; + public static CipherSuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = null; + public static CipherSuite TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = null; + public static CipherSuite TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = null; + public static CipherSuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = null; + public static CipherSuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = null; + public static CipherSuite TLS_ECDHE_RSA_WITH_NULL_SHA = null; + public static CipherSuite TLS_ECDHE_RSA_WITH_RC4_128_SHA = null; + public static CipherSuite TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = null; + public static CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = null; + public static CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = null; + public static CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = null; + public static CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = null; + public static CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = null; + public static CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = null; + public static CipherSuite TLS_ECDH_ECDSA_WITH_NULL_SHA = null; + public static CipherSuite TLS_ECDH_ECDSA_WITH_RC4_128_SHA = null; + public static CipherSuite TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = null; + public static CipherSuite TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = null; + public static CipherSuite TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = null; + public static CipherSuite TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = null; + public static CipherSuite TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = null; + public static CipherSuite TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = null; + public static CipherSuite TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = null; + public static CipherSuite TLS_ECDH_RSA_WITH_NULL_SHA = null; + public static CipherSuite TLS_ECDH_RSA_WITH_RC4_128_SHA = null; + public static CipherSuite TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = null; + public static CipherSuite TLS_ECDH_anon_WITH_AES_128_CBC_SHA = null; + public static CipherSuite TLS_ECDH_anon_WITH_AES_256_CBC_SHA = null; + public static CipherSuite TLS_ECDH_anon_WITH_NULL_SHA = null; + public static CipherSuite TLS_ECDH_anon_WITH_RC4_128_SHA = null; + public static CipherSuite TLS_EMPTY_RENEGOTIATION_INFO_SCSV = null; + public static CipherSuite TLS_FALLBACK_SCSV = null; + public static CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 = null; + public static CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA = null; + public static CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_MD5 = null; + public static CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_SHA = null; + public static CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_MD5 = null; + public static CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_SHA = null; + public static CipherSuite TLS_KRB5_WITH_DES_CBC_MD5 = null; + public static CipherSuite TLS_KRB5_WITH_DES_CBC_SHA = null; + public static CipherSuite TLS_KRB5_WITH_RC4_128_MD5 = null; + public static CipherSuite TLS_KRB5_WITH_RC4_128_SHA = null; + public static CipherSuite TLS_PSK_WITH_3DES_EDE_CBC_SHA = null; + public static CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA = null; + public static CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA = null; + public static CipherSuite TLS_PSK_WITH_RC4_128_SHA = null; + public static CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = null; + public static CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = null; + public static CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = null; + public static CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = null; + public static CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA256 = null; + public static CipherSuite TLS_RSA_WITH_AES_128_GCM_SHA256 = null; + public static CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = null; + public static CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA256 = null; + public static CipherSuite TLS_RSA_WITH_AES_256_GCM_SHA384 = null; + public static CipherSuite TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = null; + public static CipherSuite TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = null; + public static CipherSuite TLS_RSA_WITH_DES_CBC_SHA = null; + public static CipherSuite TLS_RSA_WITH_NULL_MD5 = null; + public static CipherSuite TLS_RSA_WITH_NULL_SHA = null; + public static CipherSuite TLS_RSA_WITH_NULL_SHA256 = null; + public static CipherSuite TLS_RSA_WITH_RC4_128_MD5 = null; + public static CipherSuite TLS_RSA_WITH_RC4_128_SHA = null; + public static CipherSuite TLS_RSA_WITH_SEED_CBC_SHA = null; + + public static CipherSuite forJavaName(String p0) { + return null; + } + + public static CipherSuite.Companion Companion = null; + + static public class Companion { + protected Companion() {} + + public final CipherSuite forJavaName(String p0) { + return null; + } + + public final Comparator getORDER_BY_NAME$okhttp() { + return null; + } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Connection.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Connection.java new file mode 100644 index 00000000000..636a95bccc8 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Connection.java @@ -0,0 +1,16 @@ +// Generated automatically from okhttp3.Connection for testing purposes + +package okhttp3; + +import java.net.Socket; +import okhttp3.Handshake; +import okhttp3.Protocol; +import okhttp3.Route; + +public interface Connection +{ + Handshake handshake(); + Protocol protocol(); + Route route(); + Socket socket(); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/ConnectionPool.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/ConnectionPool.java new file mode 100644 index 00000000000..ec315626985 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/ConnectionPool.java @@ -0,0 +1,17 @@ +// Generated automatically from okhttp3.ConnectionPool for testing purposes + +package okhttp3; + +import java.util.concurrent.TimeUnit; +import okhttp3.internal.connection.RealConnectionPool; + +public class ConnectionPool +{ + public ConnectionPool(){} + public ConnectionPool(RealConnectionPool p0){} + public ConnectionPool(int p0, long p1, TimeUnit p2){} + public final RealConnectionPool getDelegate$okhttp(){ return null; } + public final int connectionCount(){ return 0; } + public final int idleConnectionCount(){ return 0; } + public final void evictAll(){} +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/ConnectionSpec.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/ConnectionSpec.java new file mode 100644 index 00000000000..9f8d14b4714 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/ConnectionSpec.java @@ -0,0 +1,58 @@ +// Generated automatically from okhttp3.ConnectionSpec for testing purposes + +package okhttp3; + +import java.util.List; +import javax.net.ssl.SSLSocket; +import okhttp3.CipherSuite; +import okhttp3.TlsVersion; + +public class ConnectionSpec { + protected ConnectionSpec() {} + + public ConnectionSpec(boolean p0, boolean p1, String[] p2, String[] p3) {} + + public String toString() { + return null; + } + + public boolean equals(Object p0) { + return false; + } + + public final List cipherSuites() { + return null; + } + + public final List tlsVersions() { + return null; + } + + public final boolean isCompatible(SSLSocket p0) { + return false; + } + + public final boolean isTls() { + return false; + } + + public final boolean supportsTlsExtensions() { + return false; + } + + public final void apply$okhttp(SSLSocket p0, boolean p1) {} + + public int hashCode() { + return 0; + } + + public static ConnectionSpec CLEARTEXT = null; + public static ConnectionSpec COMPATIBLE_TLS = null; + public static ConnectionSpec MODERN_TLS = null; + public static ConnectionSpec RESTRICTED_TLS = null; + public static ConnectionSpec.Companion Companion = null; + + static public class Companion { + protected Companion() {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Cookie.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Cookie.java new file mode 100644 index 00000000000..3ffd4a2a270 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Cookie.java @@ -0,0 +1,93 @@ +// Generated automatically from okhttp3.Cookie for testing purposes + +package okhttp3; + +import java.util.List; +import okhttp3.Headers; +import okhttp3.HttpUrl; + +public class Cookie { + protected Cookie() {} + + public String toString() { + return null; + } + + public boolean equals(Object p0) { + return false; + } + + public final String domain() { + return null; + } + + public final String name() { + return null; + } + + public final String path() { + return null; + } + + public final String toString$okhttp(boolean p0) { + return null; + } + + public final String value() { + return null; + } + + public final boolean hostOnly() { + return false; + } + + public final boolean httpOnly() { + return false; + } + + public final boolean matches(HttpUrl p0) { + return false; + } + + public final boolean persistent() { + return false; + } + + public final boolean secure() { + return false; + } + + public final long expiresAt() { + return 0; + } + + public int hashCode() { + return 0; + } + + public static Cookie parse(HttpUrl p0, String p1) { + return null; + } + + public static Cookie.Companion Companion = null; + + public static List parseAll(HttpUrl p0, Headers p1) { + return null; + } + + static public class Companion { + protected Companion() {} + + public final Cookie parse$okhttp(long p0, HttpUrl p1, String p2) { + return null; + } + + public final Cookie parse(HttpUrl p0, String p1) { + return null; + } + + public final List parseAll(HttpUrl p0, Headers p1) { + return null; + } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CookieJar.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CookieJar.java new file mode 100644 index 00000000000..59d63069688 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/CookieJar.java @@ -0,0 +1,19 @@ +// Generated automatically from okhttp3.CookieJar for testing purposes + +package okhttp3; + +import java.util.List; +import okhttp3.Cookie; +import okhttp3.HttpUrl; + +public interface CookieJar +{ + List loadForRequest(HttpUrl p0); + static CookieJar NO_COOKIES = null; + static CookieJar.Companion Companion = null; + static public class Companion + { + protected Companion() {} + } + void saveFromResponse(HttpUrl p0, List p1); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Dispatcher.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Dispatcher.java new file mode 100644 index 00000000000..ca74ca9e775 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Dispatcher.java @@ -0,0 +1,62 @@ +// Generated automatically from okhttp3.Dispatcher for testing purposes + +package okhttp3; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import okhttp3.Call; +import okhttp3.internal.connection.RealCall; + +public class Dispatcher { + public Dispatcher() {} + + public Dispatcher(ExecutorService p0) {} + + public final ExecutorService executorService() { + return null; + } + + public final List queuedCalls() { + return null; + } + + public final List runningCalls() { + return null; + } + + public final Runnable getIdleCallback() { + return null; + } + + public final int getMaxRequests() { + return 0; + } + + public final int getMaxRequestsPerHost() { + return 0; + } + + public final int queuedCallsCount() { + return 0; + } + + public final int runningCallsCount() { + return 0; + } + + public final void cancelAll() {} + + public final void enqueue$okhttp(RealCall.AsyncCall p0) {} + + public final void executed$okhttp(RealCall p0) {} + + public final void finished$okhttp(RealCall p0) {} + + public final void finished$okhttp(RealCall.AsyncCall p0) {} + + public final void setIdleCallback(Runnable p0) {} + + public final void setMaxRequests(int p0) {} + + public final void setMaxRequestsPerHost(int p0) {} +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Dns.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Dns.java new file mode 100644 index 00000000000..6d31f149178 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Dns.java @@ -0,0 +1,17 @@ +// Generated automatically from okhttp3.Dns for testing purposes + +package okhttp3; + +import java.net.InetAddress; +import java.util.List; + +public interface Dns +{ + List lookup(String p0); + static Dns SYSTEM = null; + static Dns.Companion Companion = null; + static public class Companion + { + protected Companion() {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/EventListener.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/EventListener.java new file mode 100644 index 00000000000..994ecdf8183 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/EventListener.java @@ -0,0 +1,60 @@ +// Generated automatically from okhttp3.EventListener for testing purposes + +package okhttp3; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.util.List; +import okhttp3.Call; +import okhttp3.Connection; +import okhttp3.Handshake; +import okhttp3.HttpUrl; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; + +abstract public class EventListener +{ + public EventListener(){} + public static EventListener NONE = null; + public static EventListener.Companion Companion = null; + public void cacheConditionalHit(Call p0, Response p1){} + public void cacheHit(Call p0, Response p1){} + public void cacheMiss(Call p0){} + public void callEnd(Call p0){} + public void callFailed(Call p0, IOException p1){} + public void callStart(Call p0){} + public void canceled(Call p0){} + public void connectEnd(Call p0, InetSocketAddress p1, Proxy p2, Protocol p3){} + public void connectFailed(Call p0, InetSocketAddress p1, Proxy p2, Protocol p3, IOException p4){} + public void connectStart(Call p0, InetSocketAddress p1, Proxy p2){} + public void connectionAcquired(Call p0, Connection p1){} + public void connectionReleased(Call p0, Connection p1){} + public void dnsEnd(Call p0, String p1, List p2){} + public void dnsStart(Call p0, String p1){} + public void proxySelectEnd(Call p0, HttpUrl p1, List p2){} + public void proxySelectStart(Call p0, HttpUrl p1){} + public void requestBodyEnd(Call p0, long p1){} + public void requestBodyStart(Call p0){} + public void requestFailed(Call p0, IOException p1){} + public void requestHeadersEnd(Call p0, Request p1){} + public void requestHeadersStart(Call p0){} + public void responseBodyEnd(Call p0, long p1){} + public void responseBodyStart(Call p0){} + public void responseFailed(Call p0, IOException p1){} + public void responseHeadersEnd(Call p0, Response p1){} + public void responseHeadersStart(Call p0){} + public void satisfactionFailure(Call p0, Response p1){} + public void secureConnectEnd(Call p0, Handshake p1){} + public void secureConnectStart(Call p0){} + static public class Companion + { + protected Companion() {} + } + static public interface Factory + { + EventListener create(Call p0); + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Handshake.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Handshake.java new file mode 100644 index 00000000000..2f97dee0c4c --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Handshake.java @@ -0,0 +1,78 @@ +// Generated automatically from okhttp3.Handshake for testing purposes + +package okhttp3; + +import java.security.Principal; +import java.security.cert.Certificate; +import java.util.List; +import javax.net.ssl.SSLSession; +import kotlin.jvm.functions.Function0; +import okhttp3.CipherSuite; +import okhttp3.TlsVersion; + +public class Handshake { + protected Handshake() {} + + public Handshake(TlsVersion p0, CipherSuite p1, List p2, + Function0> p3) {} + + public String toString() { + return null; + } + + public boolean equals(Object p0) { + return false; + } + + public final CipherSuite cipherSuite() { + return null; + } + + public final List localCertificates() { + return null; + } + + public final List peerCertificates() { + return null; + } + + public final Principal localPrincipal() { + return null; + } + + public final Principal peerPrincipal() { + return null; + } + + public final TlsVersion tlsVersion() { + return null; + } + + public int hashCode() { + return 0; + } + + public static Handshake get(SSLSession p0) { + return null; + } + + public static Handshake get(TlsVersion p0, CipherSuite p1, List p2, + List p3) { + return null; + } + + public static Handshake.Companion Companion = null; + + static public class Companion { + protected Companion() {} + + public final Handshake get(SSLSession p0) { + return null; + } + + public final Handshake get(TlsVersion p0, CipherSuite p1, List p2, + List p3) { + return null; + } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Headers.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Headers.java new file mode 100644 index 00000000000..1d19626d587 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Headers.java @@ -0,0 +1,161 @@ +// Generated automatically from okhttp3.Headers for testing purposes + +package okhttp3; + +import java.time.Instant; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import kotlin.Pair; +import kotlin.jvm.internal.markers.KMappedMarker; + +public class Headers implements Iterable>, KMappedMarker { + protected Headers() {} + + public Iterator> iterator() { + return null; + } + + public String toString() { + return null; + } + + public boolean equals(Object p0) { + return false; + } + + public final Date getDate(String p0) { + return null; + } + + public final Headers.Builder newBuilder() { + return null; + } + + public final Instant getInstant(String p0) { + return null; + } + + public final List values(String p0) { + return null; + } + + public final Map> toMultimap() { + return null; + } + + public final Set names() { + return null; + } + + public final String get(String p0) { + return null; + } + + public final String name(int p0) { + return null; + } + + public final String value(int p0) { + return null; + } + + public final int size() { + return 0; + } + + public final long byteCount() { + return 0; + } + + public int hashCode() { + return 0; + } + + public static Headers of(Map p0) { + return null; + } + + public static Headers of(String... p0) { + return null; + } + + public static Headers.Companion Companion = null; + + static public class Builder { + public Builder() {} + + public final Headers build() { + return null; + } + + public final Headers.Builder add(String p0) { + return null; + } + + public final Headers.Builder add(String p0, Date p1) { + return null; + } + + public final Headers.Builder add(String p0, Instant p1) { + return null; + } + + public final Headers.Builder add(String p0, String p1) { + return null; + } + + public final Headers.Builder addAll(Headers p0) { + return null; + } + + public final Headers.Builder addLenient$okhttp(String p0) { + return null; + } + + public final Headers.Builder addLenient$okhttp(String p0, String p1) { + return null; + } + + public final Headers.Builder addUnsafeNonAscii(String p0, String p1) { + return null; + } + + public final Headers.Builder removeAll(String p0) { + return null; + } + + public final Headers.Builder set(String p0, Date p1) { + return null; + } + + public final Headers.Builder set(String p0, Instant p1) { + return null; + } + + public final Headers.Builder set(String p0, String p1) { + return null; + } + + public final List getNamesAndValues$okhttp() { + return null; + } + + public final String get(String p0) { + return null; + } + } + static public class Companion { + protected Companion() {} + + public final Headers of(Map p0) { + return null; + } + + public final Headers of(String... p0) { + return null; + } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/HttpUrl.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/HttpUrl.java new file mode 100644 index 00000000000..5fef4d9606d --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/HttpUrl.java @@ -0,0 +1,390 @@ +// Generated automatically from okhttp3.HttpUrl for testing purposes + +package okhttp3; + +import java.net.URI; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Set; + +public class HttpUrl { + protected HttpUrl() {} + + public HttpUrl(String p0, String p1, String p2, String p3, int p4, List p5, + List p6, String p7, String p8) {} + + public String toString() { + return null; + } + + public boolean equals(Object p0) { + return false; + } + + public final HttpUrl resolve(String p0) { + return null; + } + + public final HttpUrl.Builder newBuilder() { + return null; + } + + public final HttpUrl.Builder newBuilder(String p0) { + return null; + } + + public final List encodedPathSegments() { + return null; + } + + public final List pathSegments() { + return null; + } + + public final List queryParameterValues(String p0) { + return null; + } + + public final Set queryParameterNames() { + return null; + } + + public final String encodedFragment() { + return null; + } + + public final String encodedPassword() { + return null; + } + + public final String encodedPath() { + return null; + } + + public final String encodedQuery() { + return null; + } + + public final String encodedUsername() { + return null; + } + + public final String fragment() { + return null; + } + + public final String host() { + return null; + } + + public final String password() { + return null; + } + + public final String query() { + return null; + } + + public final String queryParameter(String p0) { + return null; + } + + public final String queryParameterName(int p0) { + return null; + } + + public final String queryParameterValue(int p0) { + return null; + } + + public final String redact() { + return null; + } + + public final String scheme() { + return null; + } + + public final String topPrivateDomain() { + return null; + } + + public final String username() { + return null; + } + + public final URI uri() { + return null; + } + + public final URL url() { + return null; + } + + public final boolean isHttps() { + return false; + } + + public final int pathSize() { + return 0; + } + + public final int port() { + return 0; + } + + public final int querySize() { + return 0; + } + + public int hashCode() { + return 0; + } + + public static HttpUrl get(String p0) { + return null; + } + + public static HttpUrl get(URI p0) { + return null; + } + + public static HttpUrl get(URL p0) { + return null; + } + + public static HttpUrl parse(String p0) { + return null; + } + + public static HttpUrl.Companion Companion = null; + public static String FORM_ENCODE_SET = null; + public static String FRAGMENT_ENCODE_SET = null; + public static String FRAGMENT_ENCODE_SET_URI = null; + public static String PASSWORD_ENCODE_SET = null; + public static String PATH_SEGMENT_ENCODE_SET = null; + public static String PATH_SEGMENT_ENCODE_SET_URI = null; + public static String QUERY_COMPONENT_ENCODE_SET = null; + public static String QUERY_COMPONENT_ENCODE_SET_URI = null; + public static String QUERY_COMPONENT_REENCODE_SET = null; + public static String QUERY_ENCODE_SET = null; + public static String USERNAME_ENCODE_SET = null; + + public static int defaultPort(String p0) { + return 0; + } + + static public class Builder { + public Builder() {} + + public String toString() { + return null; + } + + public final HttpUrl build() { + return null; + } + + public final HttpUrl.Builder addEncodedPathSegment(String p0) { + return null; + } + + public final HttpUrl.Builder addEncodedPathSegments(String p0) { + return null; + } + + public final HttpUrl.Builder addEncodedQueryParameter(String p0, String p1) { + return null; + } + + public final HttpUrl.Builder addPathSegment(String p0) { + return null; + } + + public final HttpUrl.Builder addPathSegments(String p0) { + return null; + } + + public final HttpUrl.Builder addQueryParameter(String p0, String p1) { + return null; + } + + public final HttpUrl.Builder encodedFragment(String p0) { + return null; + } + + public final HttpUrl.Builder encodedPassword(String p0) { + return null; + } + + public final HttpUrl.Builder encodedPath(String p0) { + return null; + } + + public final HttpUrl.Builder encodedQuery(String p0) { + return null; + } + + public final HttpUrl.Builder encodedUsername(String p0) { + return null; + } + + public final HttpUrl.Builder fragment(String p0) { + return null; + } + + public final HttpUrl.Builder host(String p0) { + return null; + } + + public final HttpUrl.Builder parse$okhttp(HttpUrl p0, String p1) { + return null; + } + + public final HttpUrl.Builder password(String p0) { + return null; + } + + public final HttpUrl.Builder port(int p0) { + return null; + } + + public final HttpUrl.Builder query(String p0) { + return null; + } + + public final HttpUrl.Builder reencodeForUri$okhttp() { + return null; + } + + public final HttpUrl.Builder removeAllEncodedQueryParameters(String p0) { + return null; + } + + public final HttpUrl.Builder removeAllQueryParameters(String p0) { + return null; + } + + public final HttpUrl.Builder removePathSegment(int p0) { + return null; + } + + public final HttpUrl.Builder scheme(String p0) { + return null; + } + + public final HttpUrl.Builder setEncodedPathSegment(int p0, String p1) { + return null; + } + + public final HttpUrl.Builder setEncodedQueryParameter(String p0, String p1) { + return null; + } + + public final HttpUrl.Builder setPathSegment(int p0, String p1) { + return null; + } + + public final HttpUrl.Builder setQueryParameter(String p0, String p1) { + return null; + } + + public final HttpUrl.Builder username(String p0) { + return null; + } + + public final List getEncodedPathSegments$okhttp() { + return null; + } + + public final List getEncodedQueryNamesAndValues$okhttp() { + return null; + } + + public final String getEncodedFragment$okhttp() { + return null; + } + + public final String getEncodedPassword$okhttp() { + return null; + } + + public final String getEncodedUsername$okhttp() { + return null; + } + + public final String getHost$okhttp() { + return null; + } + + public final String getScheme$okhttp() { + return null; + } + + public final int getPort$okhttp() { + return 0; + } + + public final void setEncodedFragment$okhttp(String p0) {} + + public final void setEncodedPassword$okhttp(String p0) {} + + public final void setEncodedQueryNamesAndValues$okhttp(List p0) {} + + public final void setEncodedUsername$okhttp(String p0) {} + + public final void setHost$okhttp(String p0) {} + + public final void setPort$okhttp(int p0) {} + + public final void setScheme$okhttp(String p0) {} + + public static HttpUrl.Builder.Companion Companion = null; + public static String INVALID_HOST = null; + + static public class Companion { + protected Companion() {} + } + } + static public class Companion { + protected Companion() {} + + public final HttpUrl get(String p0) { + return null; + } + + public final HttpUrl get(URI p0) { + return null; + } + + public final HttpUrl get(URL p0) { + return null; + } + + public final HttpUrl parse(String p0) { + return null; + } + + public final List toQueryNamesAndValues$okhttp(String p0) { + return null; + } + + public final String canonicalize$okhttp(String p0, int p1, int p2, String p3, boolean p4, + boolean p5, boolean p6, boolean p7, Charset p8) { + return null; + } + + public final String percentDecode$okhttp(String p0, int p1, int p2, boolean p3) { + return null; + } + + public final int defaultPort(String p0) { + return 0; + } + + public final void toPathString$okhttp(List p0, StringBuilder p1) {} + + public final void toQueryString$okhttp(List p0, StringBuilder p1) {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Interceptor.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Interceptor.java new file mode 100644 index 00000000000..db6c0e27b94 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Interceptor.java @@ -0,0 +1,34 @@ +// Generated automatically from okhttp3.Interceptor for testing purposes + +package okhttp3; + +import java.util.concurrent.TimeUnit; +import kotlin.jvm.functions.Function1; +import okhttp3.Call; +import okhttp3.Connection; +import okhttp3.Request; +import okhttp3.Response; + +public interface Interceptor +{ + Response intercept(Interceptor.Chain p0); + static Interceptor.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final Interceptor invoke(Function1 p0){ return null; } + } + static public interface Chain + { + Call call(); + Connection connection(); + Interceptor.Chain withConnectTimeout(int p0, TimeUnit p1); + Interceptor.Chain withReadTimeout(int p0, TimeUnit p1); + Interceptor.Chain withWriteTimeout(int p0, TimeUnit p1); + Request request(); + Response proceed(Request p0); + int connectTimeoutMillis(); + int readTimeoutMillis(); + int writeTimeoutMillis(); + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/MediaType.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/MediaType.java new file mode 100644 index 00000000000..2b3a2f0117a --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/MediaType.java @@ -0,0 +1,63 @@ +// Generated automatically from okhttp3.MediaType for testing purposes + +package okhttp3; + +import java.nio.charset.Charset; + +public class MediaType { + protected MediaType() {} + + public String toString() { + return null; + } + + public boolean equals(Object p0) { + return false; + } + + public final Charset charset() { + return null; + } + + public final Charset charset(Charset p0) { + return null; + } + + public final String parameter(String p0) { + return null; + } + + public final String subtype() { + return null; + } + + public final String type() { + return null; + } + + public int hashCode() { + return 0; + } + + public static MediaType get(String p0) { + return null; + } + + public static MediaType parse(String p0) { + return null; + } + + public static MediaType.Companion Companion = null; + + static public class Companion { + protected Companion() {} + + public final MediaType get(String p0) { + return null; + } + + public final MediaType parse(String p0) { + return null; + } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/OkHttpClient.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/OkHttpClient.java new file mode 100644 index 00000000000..2af0180eb36 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/OkHttpClient.java @@ -0,0 +1,528 @@ +// Generated automatically from okhttp3.OkHttpClient for testing purposes + +package okhttp3; + +import java.net.Proxy; +import java.net.ProxySelector; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.TimeUnit; +import javax.net.SocketFactory; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.X509TrustManager; +import kotlin.jvm.functions.Function1; +import okhttp3.Authenticator; +import okhttp3.Cache; +import okhttp3.Call; +import okhttp3.CertificatePinner; +import okhttp3.ConnectionPool; +import okhttp3.ConnectionSpec; +import okhttp3.CookieJar; +import okhttp3.Dispatcher; +import okhttp3.Dns; +import okhttp3.EventListener; +import okhttp3.Interceptor; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; +import okhttp3.internal.connection.RouteDatabase; +import okhttp3.internal.tls.CertificateChainCleaner; + +public class OkHttpClient implements Call.Factory, Cloneable, WebSocket.Factory { + public Call newCall(Request p0) { + return null; + } + + public Object clone() { + return null; + } + + public OkHttpClient() {} + + public OkHttpClient(OkHttpClient.Builder p0) {} + + public OkHttpClient.Builder newBuilder() { + return null; + } + + public WebSocket newWebSocket(Request p0, WebSocketListener p1) { + return null; + } + + public final Authenticator authenticator() { + return null; + } + + public final Authenticator proxyAuthenticator() { + return null; + } + + public final Cache cache() { + return null; + } + + public final CertificateChainCleaner certificateChainCleaner() { + return null; + } + + public final CertificatePinner certificatePinner() { + return null; + } + + public final ConnectionPool connectionPool() { + return null; + } + + public final CookieJar cookieJar() { + return null; + } + + public final Dispatcher dispatcher() { + return null; + } + + public final Dns dns() { + return null; + } + + public final EventListener.Factory eventListenerFactory() { + return null; + } + + public final HostnameVerifier hostnameVerifier() { + return null; + } + + public final List connectionSpecs() { + return null; + } + + public final List interceptors() { + return null; + } + + public final List networkInterceptors() { + return null; + } + + public final List protocols() { + return null; + } + + public final Proxy proxy() { + return null; + } + + public final ProxySelector proxySelector() { + return null; + } + + public final RouteDatabase getRouteDatabase() { + return null; + } + + public final SSLSocketFactory sslSocketFactory() { + return null; + } + + public final SocketFactory socketFactory() { + return null; + } + + public final X509TrustManager x509TrustManager() { + return null; + } + + public final boolean followRedirects() { + return false; + } + + public final boolean followSslRedirects() { + return false; + } + + public final boolean retryOnConnectionFailure() { + return false; + } + + public final int callTimeoutMillis() { + return 0; + } + + public final int connectTimeoutMillis() { + return 0; + } + + public final int pingIntervalMillis() { + return 0; + } + + public final int readTimeoutMillis() { + return 0; + } + + public final int writeTimeoutMillis() { + return 0; + } + + public final long minWebSocketMessageToCompress() { + return 0; + } + + public static OkHttpClient.Companion Companion = null; + + static public class Builder { + public Builder() {} + + public Builder(OkHttpClient p0) {} + + public final Authenticator getAuthenticator$okhttp() { + return null; + } + + public final Authenticator getProxyAuthenticator$okhttp() { + return null; + } + + public final Cache getCache$okhttp() { + return null; + } + + public final CertificateChainCleaner getCertificateChainCleaner$okhttp() { + return null; + } + + public final CertificatePinner getCertificatePinner$okhttp() { + return null; + } + + public final ConnectionPool getConnectionPool$okhttp() { + return null; + } + + public final CookieJar getCookieJar$okhttp() { + return null; + } + + public final Dispatcher getDispatcher$okhttp() { + return null; + } + + public final Dns getDns$okhttp() { + return null; + } + + public final EventListener.Factory getEventListenerFactory$okhttp() { + return null; + } + + public final HostnameVerifier getHostnameVerifier$okhttp() { + return null; + } + + public final List getConnectionSpecs$okhttp() { + return null; + } + + public final List getInterceptors$okhttp() { + return null; + } + + public final List getNetworkInterceptors$okhttp() { + return null; + } + + public final List interceptors() { + return null; + } + + public final List networkInterceptors() { + return null; + } + + public final List getProtocols$okhttp() { + return null; + } + + public final OkHttpClient build() { + return null; + } + + public final OkHttpClient.Builder addInterceptor( + Function1 p0) { + return null; + } + + public final OkHttpClient.Builder addNetworkInterceptor( + Function1 p0) { + return null; + } + + public final OkHttpClient.Builder addInterceptor(Interceptor p0) { + return null; + } + + public final OkHttpClient.Builder addNetworkInterceptor(Interceptor p0) { + return null; + } + + public final OkHttpClient.Builder authenticator(Authenticator p0) { + return null; + } + + public final OkHttpClient.Builder cache(Cache p0) { + return null; + } + + public final OkHttpClient.Builder callTimeout(Duration p0) { + return null; + } + + public final OkHttpClient.Builder callTimeout(long p0, TimeUnit p1) { + return null; + } + + public final OkHttpClient.Builder certificatePinner(CertificatePinner p0) { + return null; + } + + public final OkHttpClient.Builder connectTimeout(Duration p0) { + return null; + } + + public final OkHttpClient.Builder connectTimeout(long p0, TimeUnit p1) { + return null; + } + + public final OkHttpClient.Builder connectionPool(ConnectionPool p0) { + return null; + } + + public final OkHttpClient.Builder connectionSpecs(List p0) { + return null; + } + + public final OkHttpClient.Builder cookieJar(CookieJar p0) { + return null; + } + + public final OkHttpClient.Builder dispatcher(Dispatcher p0) { + return null; + } + + public final OkHttpClient.Builder dns(Dns p0) { + return null; + } + + public final OkHttpClient.Builder eventListener(EventListener p0) { + return null; + } + + public final OkHttpClient.Builder eventListenerFactory(EventListener.Factory p0) { + return null; + } + + public final OkHttpClient.Builder followRedirects(boolean p0) { + return null; + } + + public final OkHttpClient.Builder followSslRedirects(boolean p0) { + return null; + } + + public final OkHttpClient.Builder hostnameVerifier(HostnameVerifier p0) { + return null; + } + + public final OkHttpClient.Builder minWebSocketMessageToCompress(long p0) { + return null; + } + + public final OkHttpClient.Builder pingInterval(Duration p0) { + return null; + } + + public final OkHttpClient.Builder pingInterval(long p0, TimeUnit p1) { + return null; + } + + public final OkHttpClient.Builder protocols(List p0) { + return null; + } + + public final OkHttpClient.Builder proxy(Proxy p0) { + return null; + } + + public final OkHttpClient.Builder proxyAuthenticator(Authenticator p0) { + return null; + } + + public final OkHttpClient.Builder proxySelector(ProxySelector p0) { + return null; + } + + public final OkHttpClient.Builder readTimeout(Duration p0) { + return null; + } + + public final OkHttpClient.Builder readTimeout(long p0, TimeUnit p1) { + return null; + } + + public final OkHttpClient.Builder retryOnConnectionFailure(boolean p0) { + return null; + } + + public final OkHttpClient.Builder socketFactory(SocketFactory p0) { + return null; + } + + public final OkHttpClient.Builder sslSocketFactory(SSLSocketFactory p0) { + return null; + } + + public final OkHttpClient.Builder sslSocketFactory(SSLSocketFactory p0, + X509TrustManager p1) { + return null; + } + + public final OkHttpClient.Builder writeTimeout(Duration p0) { + return null; + } + + public final OkHttpClient.Builder writeTimeout(long p0, TimeUnit p1) { + return null; + } + + public final Proxy getProxy$okhttp() { + return null; + } + + public final ProxySelector getProxySelector$okhttp() { + return null; + } + + public final RouteDatabase getRouteDatabase$okhttp() { + return null; + } + + public final SSLSocketFactory getSslSocketFactoryOrNull$okhttp() { + return null; + } + + public final SocketFactory getSocketFactory$okhttp() { + return null; + } + + public final X509TrustManager getX509TrustManagerOrNull$okhttp() { + return null; + } + + public final boolean getFollowRedirects$okhttp() { + return false; + } + + public final boolean getFollowSslRedirects$okhttp() { + return false; + } + + public final boolean getRetryOnConnectionFailure$okhttp() { + return false; + } + + public final int getCallTimeout$okhttp() { + return 0; + } + + public final int getConnectTimeout$okhttp() { + return 0; + } + + public final int getPingInterval$okhttp() { + return 0; + } + + public final int getReadTimeout$okhttp() { + return 0; + } + + public final int getWriteTimeout$okhttp() { + return 0; + } + + public final long getMinWebSocketMessageToCompress$okhttp() { + return 0; + } + + public final void setAuthenticator$okhttp(Authenticator p0) {} + + public final void setCache$okhttp(Cache p0) {} + + public final void setCallTimeout$okhttp(int p0) {} + + public final void setCertificateChainCleaner$okhttp(CertificateChainCleaner p0) {} + + public final void setCertificatePinner$okhttp(CertificatePinner p0) {} + + public final void setConnectTimeout$okhttp(int p0) {} + + public final void setConnectionPool$okhttp(ConnectionPool p0) {} + + public final void setConnectionSpecs$okhttp(List p0) {} + + public final void setCookieJar$okhttp(CookieJar p0) {} + + public final void setDispatcher$okhttp(Dispatcher p0) {} + + public final void setDns$okhttp(Dns p0) {} + + public final void setEventListenerFactory$okhttp(EventListener.Factory p0) {} + + public final void setFollowRedirects$okhttp(boolean p0) {} + + public final void setFollowSslRedirects$okhttp(boolean p0) {} + + public final void setHostnameVerifier$okhttp(HostnameVerifier p0) {} + + public final void setMinWebSocketMessageToCompress$okhttp(long p0) {} + + public final void setPingInterval$okhttp(int p0) {} + + public final void setProtocols$okhttp(List p0) {} + + public final void setProxy$okhttp(Proxy p0) {} + + public final void setProxyAuthenticator$okhttp(Authenticator p0) {} + + public final void setProxySelector$okhttp(ProxySelector p0) {} + + public final void setReadTimeout$okhttp(int p0) {} + + public final void setRetryOnConnectionFailure$okhttp(boolean p0) {} + + public final void setRouteDatabase$okhttp(RouteDatabase p0) {} + + public final void setSocketFactory$okhttp(SocketFactory p0) {} + + public final void setSslSocketFactoryOrNull$okhttp(SSLSocketFactory p0) {} + + public final void setWriteTimeout$okhttp(int p0) {} + + public final void setX509TrustManagerOrNull$okhttp(X509TrustManager p0) {} + } + static public class Companion { + protected Companion() {} + + public final List getDEFAULT_CONNECTION_SPECS$okhttp() { + return null; + } + + public final List getDEFAULT_PROTOCOLS$okhttp() { + return null; + } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Protocol.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Protocol.java new file mode 100644 index 00000000000..da4c21e9ee2 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Protocol.java @@ -0,0 +1,18 @@ +// Generated automatically from okhttp3.Protocol for testing purposes + +package okhttp3; + + +public enum Protocol +{ + H2_PRIOR_KNOWLEDGE, HTTP_1_0, HTTP_1_1, HTTP_2, QUIC, SPDY_3; + private Protocol() {} + public String toString(){ return null; } + public static Protocol get(String p0){ return null; } + public static Protocol.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final Protocol get(String p0){ return null; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Request.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Request.java new file mode 100644 index 00000000000..f00e4c89c40 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Request.java @@ -0,0 +1,182 @@ +// Generated automatically from okhttp3.Request for testing purposes + +package okhttp3; + +import java.net.URL; +import java.util.List; +import java.util.Map; +import okhttp3.CacheControl; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.RequestBody; + +public class Request { + protected Request() {} + + public Request(HttpUrl p0, String p1, Headers p2, RequestBody p3, + Map, ? extends Object> p4) {} + + public String toString() { + return null; + } + + public final T tag(Class p0) { + return null; + } + + public final CacheControl cacheControl() { + return null; + } + + public final Headers headers() { + return null; + } + + public final HttpUrl url() { + return null; + } + + public final List headers(String p0) { + return null; + } + + public final Map, Object> getTags$okhttp() { + return null; + } + + public final Object tag() { + return null; + } + + public final Request.Builder newBuilder() { + return null; + } + + public final RequestBody body() { + return null; + } + + public final String header(String p0) { + return null; + } + + public final String method() { + return null; + } + + public final boolean isHttps() { + return false; + } + + static public class Builder { + public Request.Builder tag(Class p0, T p1) { + return null; + } + + public Builder() {} + + public Builder(Request p0) {} + + public Request build() { + return null; + } + + public Request.Builder addHeader(String p0, String p1) { + return null; + } + + public Request.Builder cacheControl(CacheControl p0) { + return null; + } + + public Request.Builder delete(RequestBody p0) { + return null; + } + + public Request.Builder get() { + return null; + } + + public Request.Builder head() { + return null; + } + + public Request.Builder header(String p0, String p1) { + return null; + } + + public Request.Builder headers(Headers p0) { + return null; + } + + public Request.Builder method(String p0, RequestBody p1) { + return null; + } + + public Request.Builder patch(RequestBody p0) { + return null; + } + + public Request.Builder post(RequestBody p0) { + return null; + } + + public Request.Builder put(RequestBody p0) { + return null; + } + + public Request.Builder removeHeader(String p0) { + return null; + } + + public Request.Builder tag(Object p0) { + return null; + } + + public Request.Builder url(HttpUrl p0) { + return null; + } + + public Request.Builder url(String p0) { + return null; + } + + public Request.Builder url(URL p0) { + return null; + } + + public final Headers.Builder getHeaders$okhttp() { + return null; + } + + public final HttpUrl getUrl$okhttp() { + return null; + } + + public final Map, Object> getTags$okhttp() { + return null; + } + + public final Request.Builder delete() { + return null; + } + + public final RequestBody getBody$okhttp() { + return null; + } + + public final String getMethod$okhttp() { + return null; + } + + public final void setBody$okhttp(RequestBody p0) {} + + public final void setHeaders$okhttp(Headers.Builder p0) {} + + public final void setMethod$okhttp(String p0) {} + + public final void setTags$okhttp(Map, Object> p0) {} + + public final void setUrl$okhttp(HttpUrl p0) {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/RequestBody.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/RequestBody.java new file mode 100644 index 00000000000..a5d4133760a --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/RequestBody.java @@ -0,0 +1,49 @@ +// Generated automatically from okhttp3.RequestBody for testing purposes + +package okhttp3; + +import java.io.File; +import okhttp3.MediaType; +import okio.BufferedSink; +import okio.ByteString; + +abstract public class RequestBody +{ + public RequestBody(){} + public abstract MediaType contentType(); + public abstract void writeTo(BufferedSink p0); + public boolean isDuplex(){ return false; } + public boolean isOneShot(){ return false; } + public long contentLength(){ return 0; } + public static RequestBody create(ByteString p0, MediaType p1){ return null; } + public static RequestBody create(File p0, MediaType p1){ return null; } + public static RequestBody create(MediaType p0, ByteString p1){ return null; } + public static RequestBody create(MediaType p0, File p1){ return null; } + public static RequestBody create(MediaType p0, String p1){ return null; } + public static RequestBody create(MediaType p0, byte[] p1){ return null; } + public static RequestBody create(MediaType p0, byte[] p1, int p2){ return null; } + public static RequestBody create(MediaType p0, byte[] p1, int p2, int p3){ return null; } + public static RequestBody create(String p0, MediaType p1){ return null; } + public static RequestBody create(byte[] p0){ return null; } + public static RequestBody create(byte[] p0, MediaType p1){ return null; } + public static RequestBody create(byte[] p0, MediaType p1, int p2){ return null; } + public static RequestBody create(byte[] p0, MediaType p1, int p2, int p3){ return null; } + public static RequestBody.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final RequestBody create(ByteString p0, MediaType p1){ return null; } + public final RequestBody create(File p0, MediaType p1){ return null; } + public final RequestBody create(MediaType p0, ByteString p1){ return null; } + public final RequestBody create(MediaType p0, File p1){ return null; } + public final RequestBody create(MediaType p0, String p1){ return null; } + public final RequestBody create(MediaType p0, byte[] p1){ return null; } + public final RequestBody create(MediaType p0, byte[] p1, int p2){ return null; } + public final RequestBody create(MediaType p0, byte[] p1, int p2, int p3){ return null; } + public final RequestBody create(String p0, MediaType p1){ return null; } + public final RequestBody create(byte[] p0){ return null; } + public final RequestBody create(byte[] p0, MediaType p1){ return null; } + public final RequestBody create(byte[] p0, MediaType p1, int p2){ return null; } + public final RequestBody create(byte[] p0, MediaType p1, int p2, int p3){ return null; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Response.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Response.java new file mode 100644 index 00000000000..a13ed203c53 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Response.java @@ -0,0 +1,270 @@ +// Generated automatically from okhttp3.Response for testing purposes + +package okhttp3; + +import java.io.Closeable; +import java.util.List; +import okhttp3.CacheControl; +import okhttp3.Challenge; +import okhttp3.Handshake; +import okhttp3.Headers; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.ResponseBody; +import okhttp3.internal.connection.Exchange; + +public class Response implements Closeable { + protected Response() {} + + public Response(Request p0, Protocol p1, String p2, int p3, Handshake p4, Headers p5, + ResponseBody p6, Response p7, Response p8, Response p9, long p10, long p11, + Exchange p12) {} + + public String toString() { + return null; + } + + public final CacheControl cacheControl() { + return null; + } + + public final Exchange exchange() { + return null; + } + + public final Handshake handshake() { + return null; + } + + public final Headers headers() { + return null; + } + + public final Headers trailers() { + return null; + } + + public final List challenges() { + return null; + } + + public final List headers(String p0) { + return null; + } + + public final Protocol protocol() { + return null; + } + + public final Request request() { + return null; + } + + public final Response cacheResponse() { + return null; + } + + public final Response networkResponse() { + return null; + } + + public final Response priorResponse() { + return null; + } + + public final Response.Builder newBuilder() { + return null; + } + + public final ResponseBody body() { + return null; + } + + public final ResponseBody peekBody(long p0) { + return null; + } + + public final String header(String p0) { + return null; + } + + public final String header(String p0, String p1) { + return null; + } + + public final String message() { + return null; + } + + public final boolean isRedirect() { + return false; + } + + public final boolean isSuccessful() { + return false; + } + + public final int code() { + return 0; + } + + public final long receivedResponseAtMillis() { + return 0; + } + + public final long sentRequestAtMillis() { + return 0; + } + + public void close() {} + + static public class Builder { + public Builder() {} + + public Builder(Response p0) {} + + public Response build() { + return null; + } + + public Response.Builder addHeader(String p0, String p1) { + return null; + } + + public Response.Builder body(ResponseBody p0) { + return null; + } + + public Response.Builder cacheResponse(Response p0) { + return null; + } + + public Response.Builder code(int p0) { + return null; + } + + public Response.Builder handshake(Handshake p0) { + return null; + } + + public Response.Builder header(String p0, String p1) { + return null; + } + + public Response.Builder headers(Headers p0) { + return null; + } + + public Response.Builder message(String p0) { + return null; + } + + public Response.Builder networkResponse(Response p0) { + return null; + } + + public Response.Builder priorResponse(Response p0) { + return null; + } + + public Response.Builder protocol(Protocol p0) { + return null; + } + + public Response.Builder receivedResponseAtMillis(long p0) { + return null; + } + + public Response.Builder removeHeader(String p0) { + return null; + } + + public Response.Builder request(Request p0) { + return null; + } + + public Response.Builder sentRequestAtMillis(long p0) { + return null; + } + + public final Exchange getExchange$okhttp() { + return null; + } + + public final Handshake getHandshake$okhttp() { + return null; + } + + public final Headers.Builder getHeaders$okhttp() { + return null; + } + + public final Protocol getProtocol$okhttp() { + return null; + } + + public final Request getRequest$okhttp() { + return null; + } + + public final Response getCacheResponse$okhttp() { + return null; + } + + public final Response getNetworkResponse$okhttp() { + return null; + } + + public final Response getPriorResponse$okhttp() { + return null; + } + + public final ResponseBody getBody$okhttp() { + return null; + } + + public final String getMessage$okhttp() { + return null; + } + + public final int getCode$okhttp() { + return 0; + } + + public final long getReceivedResponseAtMillis$okhttp() { + return 0; + } + + public final long getSentRequestAtMillis$okhttp() { + return 0; + } + + public final void initExchange$okhttp(Exchange p0) {} + + public final void setBody$okhttp(ResponseBody p0) {} + + public final void setCacheResponse$okhttp(Response p0) {} + + public final void setCode$okhttp(int p0) {} + + public final void setExchange$okhttp(Exchange p0) {} + + public final void setHandshake$okhttp(Handshake p0) {} + + public final void setHeaders$okhttp(Headers.Builder p0) {} + + public final void setMessage$okhttp(String p0) {} + + public final void setNetworkResponse$okhttp(Response p0) {} + + public final void setPriorResponse$okhttp(Response p0) {} + + public final void setProtocol$okhttp(Protocol p0) {} + + public final void setReceivedResponseAtMillis$okhttp(long p0) {} + + public final void setRequest$okhttp(Request p0) {} + + public final void setSentRequestAtMillis$okhttp(long p0) {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/ResponseBody.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/ResponseBody.java new file mode 100644 index 00000000000..7cd78861bd8 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/ResponseBody.java @@ -0,0 +1,45 @@ +// Generated automatically from okhttp3.ResponseBody for testing purposes + +package okhttp3; + +import java.io.Closeable; +import java.io.InputStream; +import java.io.Reader; +import okhttp3.MediaType; +import okio.BufferedSource; +import okio.ByteString; + +abstract public class ResponseBody implements Closeable +{ + public ResponseBody(){} + public abstract BufferedSource source(); + public abstract MediaType contentType(); + public abstract long contentLength(); + public final ByteString byteString(){ return null; } + public final InputStream byteStream(){ return null; } + public final Reader charStream(){ return null; } + public final String string(){ return null; } + public final byte[] bytes(){ return null; } + public static ResponseBody create(BufferedSource p0, MediaType p1, long p2){ return null; } + public static ResponseBody create(ByteString p0, MediaType p1){ return null; } + public static ResponseBody create(MediaType p0, ByteString p1){ return null; } + public static ResponseBody create(MediaType p0, String p1){ return null; } + public static ResponseBody create(MediaType p0, byte[] p1){ return null; } + public static ResponseBody create(MediaType p0, long p1, BufferedSource p2){ return null; } + public static ResponseBody create(String p0, MediaType p1){ return null; } + public static ResponseBody create(byte[] p0, MediaType p1){ return null; } + public static ResponseBody.Companion Companion = null; + public void close(){} + static public class Companion + { + protected Companion() {} + public final ResponseBody create(BufferedSource p0, MediaType p1, long p2){ return null; } + public final ResponseBody create(ByteString p0, MediaType p1){ return null; } + public final ResponseBody create(MediaType p0, ByteString p1){ return null; } + public final ResponseBody create(MediaType p0, String p1){ return null; } + public final ResponseBody create(MediaType p0, byte[] p1){ return null; } + public final ResponseBody create(MediaType p0, long p1, BufferedSource p2){ return null; } + public final ResponseBody create(String p0, MediaType p1){ return null; } + public final ResponseBody create(byte[] p0, MediaType p1){ return null; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Route.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Route.java new file mode 100644 index 00000000000..bff177b55a0 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/Route.java @@ -0,0 +1,41 @@ +// Generated automatically from okhttp3.Route for testing purposes + +package okhttp3; + +import java.net.InetSocketAddress; +import java.net.Proxy; +import okhttp3.Address; + +public class Route { + protected Route() {} + + public Route(Address p0, Proxy p1, InetSocketAddress p2) {} + + public String toString() { + return null; + } + + public boolean equals(Object p0) { + return false; + } + + public final Address address() { + return null; + } + + public final InetSocketAddress socketAddress() { + return null; + } + + public final Proxy proxy() { + return null; + } + + public final boolean requiresTunnel() { + return false; + } + + public int hashCode() { + return 0; + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/TlsVersion.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/TlsVersion.java new file mode 100644 index 00000000000..fdcfdc9ab6d --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/TlsVersion.java @@ -0,0 +1,28 @@ +// Generated automatically from okhttp3.TlsVersion for testing purposes + +package okhttp3; + + +public enum TlsVersion { + SSL_3_0, TLS_1_0, TLS_1_1, TLS_1_2, TLS_1_3; + + private TlsVersion() {} + + public final String javaName() { + return null; + } + + public static TlsVersion forJavaName(String p0) { + return null; + } + + public static TlsVersion.Companion Companion = null; + + static public class Companion { + protected Companion() {} + + public final TlsVersion forJavaName(String p0) { + return null; + } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/WebSocket.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/WebSocket.java new file mode 100644 index 00000000000..aa987e818a9 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/WebSocket.java @@ -0,0 +1,21 @@ +// Generated automatically from okhttp3.WebSocket for testing purposes + +package okhttp3; + +import okhttp3.Request; +import okhttp3.WebSocketListener; +import okio.ByteString; + +public interface WebSocket +{ + Request request(); + boolean close(int p0, String p1); + boolean send(ByteString p0); + boolean send(String p0); + long queueSize(); + static public interface Factory + { + WebSocket newWebSocket(Request p0, WebSocketListener p1); + } + void cancel(); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/WebSocketListener.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/WebSocketListener.java new file mode 100644 index 00000000000..01db429340a --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/WebSocketListener.java @@ -0,0 +1,18 @@ +// Generated automatically from okhttp3.WebSocketListener for testing purposes + +package okhttp3; + +import okhttp3.Response; +import okhttp3.WebSocket; +import okio.ByteString; + +abstract public class WebSocketListener +{ + public WebSocketListener(){} + public void onClosed(WebSocket p0, int p1, String p2){} + public void onClosing(WebSocket p0, int p1, String p2){} + public void onFailure(WebSocket p0, Throwable p1, Response p2){} + public void onMessage(WebSocket p0, ByteString p1){} + public void onMessage(WebSocket p0, String p1){} + public void onOpen(WebSocket p0, Response p1){} +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/CacheRequest.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/CacheRequest.java new file mode 100644 index 00000000000..5407de41640 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/CacheRequest.java @@ -0,0 +1,11 @@ +// Generated automatically from okhttp3.internal.cache.CacheRequest for testing purposes + +package okhttp3.internal.cache; + +import okio.Sink; + +public interface CacheRequest +{ + Sink body(); + void abort(); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/CacheStrategy.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/CacheStrategy.java new file mode 100644 index 00000000000..1805e58c0ec --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/CacheStrategy.java @@ -0,0 +1,20 @@ +// Generated automatically from okhttp3.internal.cache.CacheStrategy for testing purposes + +package okhttp3.internal.cache; + +import okhttp3.Request; +import okhttp3.Response; + +public class CacheStrategy +{ + protected CacheStrategy() {} + public CacheStrategy(Request p0, Response p1){} + public final Request getNetworkRequest(){ return null; } + public final Response getCacheResponse(){ return null; } + public static CacheStrategy.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final boolean isCacheable(Response p0, Request p1){ return false; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/DiskLruCache.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/DiskLruCache.java new file mode 100644 index 00000000000..35a3b5fe3f3 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/cache/DiskLruCache.java @@ -0,0 +1,106 @@ +// Generated automatically from okhttp3.internal.cache.DiskLruCache for testing purposes + +package okhttp3.internal.cache; + +import java.io.Closeable; +import java.io.File; +import java.io.Flushable; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import kotlin.text.Regex; +import okhttp3.internal.concurrent.TaskRunner; +import okhttp3.internal.io.FileSystem; +import okio.BufferedSink; +import okio.Sink; +import okio.Source; + +public class DiskLruCache implements Closeable, Flushable +{ + protected DiskLruCache() {} + public DiskLruCache(FileSystem p0, File p1, int p2, int p3, long p4, TaskRunner p5){} + public class Editor + { + protected Editor() {} + public Editor(DiskLruCache.Entry p0){} + public final DiskLruCache.Entry getEntry$okhttp(){ return null; } + public final Sink newSink(int p0){ return null; } + public final Source newSource(int p0){ return null; } + public final boolean[] getWritten$okhttp(){ return null; } + public final void abort(){} + public final void commit(){} + public final void detach$okhttp(){} + } + public class Entry + { + protected Entry() {} + public Entry(String p0){} + public final DiskLruCache.Editor getCurrentEditor$okhttp(){ return null; } + public final DiskLruCache.Snapshot snapshot$okhttp(){ return null; } + public final List getCleanFiles$okhttp(){ return null; } + public final List getDirtyFiles$okhttp(){ return null; } + public final String getKey$okhttp(){ return null; } + public final boolean getReadable$okhttp(){ return false; } + public final boolean getZombie$okhttp(){ return false; } + public final int getLockingSourceCount$okhttp(){ return 0; } + public final long getSequenceNumber$okhttp(){ return 0; } + public final long[] getLengths$okhttp(){ return null; } + public final void setCurrentEditor$okhttp(DiskLruCache.Editor p0){} + public final void setLengths$okhttp(List p0){} + public final void setLockingSourceCount$okhttp(int p0){} + public final void setReadable$okhttp(boolean p0){} + public final void setSequenceNumber$okhttp(long p0){} + public final void setZombie$okhttp(boolean p0){} + public final void writeLengths$okhttp(BufferedSink p0){} + } + public class Snapshot implements Closeable + { + protected Snapshot() {} + public Snapshot(String p0, long p1, List p2, long[] p3){} + public final DiskLruCache.Editor edit(){ return null; } + public final Source getSource(int p0){ return null; } + public final String key(){ return null; } + public final long getLength(int p0){ return 0; } + public void close(){} + } + public final DiskLruCache.Editor edit(String p0){ return null; } + public final DiskLruCache.Editor edit(String p0, long p1){ return null; } + public final DiskLruCache.Snapshot get(String p0){ return null; } + public final File getDirectory(){ return null; } + public final FileSystem getFileSystem$okhttp(){ return null; } + public final Iterator snapshots(){ return null; } + public final LinkedHashMap getLruEntries$okhttp(){ return null; } + public final boolean getClosed$okhttp(){ return false; } + public final boolean isClosed(){ return false; } + public final boolean remove(String p0){ return false; } + public final boolean removeEntry$okhttp(DiskLruCache.Entry p0){ return false; } + public final int getValueCount$okhttp(){ return 0; } + public final long getMaxSize(){ return 0; } + public final long size(){ return 0; } + public final void completeEdit$okhttp(DiskLruCache.Editor p0, boolean p1){} + public final void delete(){} + public final void evictAll(){} + public final void initialize(){} + public final void rebuildJournal$okhttp(){} + public final void setClosed$okhttp(boolean p0){} + public final void setMaxSize(long p0){} + public final void trimToSize(){} + public static DiskLruCache.Companion Companion = null; + public static Regex LEGAL_KEY_PATTERN = null; + public static String CLEAN = null; + public static String DIRTY = null; + public static String JOURNAL_FILE = null; + public static String JOURNAL_FILE_BACKUP = null; + public static String JOURNAL_FILE_TEMP = null; + public static String MAGIC = null; + public static String READ = null; + public static String REMOVE = null; + public static String VERSION_1 = null; + public static long ANY_SEQUENCE_NUMBER = 0; + public void close(){} + public void flush(){} + static public class Companion + { + protected Companion() {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/Task.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/Task.java new file mode 100644 index 00000000000..b21bcb7abd6 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/Task.java @@ -0,0 +1,20 @@ +// Generated automatically from okhttp3.internal.concurrent.Task for testing purposes + +package okhttp3.internal.concurrent; + +import okhttp3.internal.concurrent.TaskQueue; + +abstract public class Task +{ + protected Task() {} + public String toString(){ return null; } + public Task(String p0, boolean p1){} + public abstract long runOnce(); + public final String getName(){ return null; } + public final TaskQueue getQueue$okhttp(){ return null; } + public final boolean getCancelable(){ return false; } + public final long getNextExecuteNanoTime$okhttp(){ return 0; } + public final void initQueue$okhttp(TaskQueue p0){} + public final void setNextExecuteNanoTime$okhttp(long p0){} + public final void setQueue$okhttp(TaskQueue p0){} +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/TaskQueue.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/TaskQueue.java new file mode 100644 index 00000000000..7e2dd674940 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/TaskQueue.java @@ -0,0 +1,35 @@ +// Generated automatically from okhttp3.internal.concurrent.TaskQueue for testing purposes + +package okhttp3.internal.concurrent; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import kotlin.Unit; +import kotlin.jvm.functions.Function0; +import okhttp3.internal.concurrent.Task; +import okhttp3.internal.concurrent.TaskRunner; + +public class TaskQueue +{ + protected TaskQueue() {} + public String toString(){ return null; } + public TaskQueue(TaskRunner p0, String p1){} + public final CountDownLatch idleLatch(){ return null; } + public final List getFutureTasks$okhttp(){ return null; } + public final List getScheduledTasks(){ return null; } + public final String getName$okhttp(){ return null; } + public final Task getActiveTask$okhttp(){ return null; } + public final TaskRunner getTaskRunner$okhttp(){ return null; } + public final boolean cancelAllAndDecide$okhttp(){ return false; } + public final boolean getCancelActiveTask$okhttp(){ return false; } + public final boolean getShutdown$okhttp(){ return false; } + public final boolean scheduleAndDecide$okhttp(Task p0, long p1, boolean p2){ return false; } + public final void cancelAll(){} + public final void execute(String p0, long p1, boolean p2, Function0 p3){} + public final void schedule(String p0, long p1, Function0 p2){} + public final void schedule(Task p0, long p1){} + public final void setActiveTask$okhttp(Task p0){} + public final void setCancelActiveTask$okhttp(boolean p0){} + public final void setShutdown$okhttp(boolean p0){} + public final void shutdown(){} +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/TaskRunner.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/TaskRunner.java new file mode 100644 index 00000000000..173c7135540 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/concurrent/TaskRunner.java @@ -0,0 +1,35 @@ +// Generated automatically from okhttp3.internal.concurrent.TaskRunner for testing purposes + +package okhttp3.internal.concurrent; + +import java.util.List; +import java.util.logging.Logger; +import okhttp3.internal.concurrent.Task; +import okhttp3.internal.concurrent.TaskQueue; + +public class TaskRunner +{ + protected TaskRunner() {} + public TaskRunner(TaskRunner.Backend p0){} + public final List activeQueues(){ return null; } + public final Task awaitTaskToRun(){ return null; } + public final TaskQueue newQueue(){ return null; } + public final TaskRunner.Backend getBackend(){ return null; } + public final void cancelAll(){} + public final void kickCoordinator$okhttp(TaskQueue p0){} + public static TaskRunner INSTANCE = null; + public static TaskRunner.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final Logger getLogger(){ return null; } + } + static public interface Backend + { + long nanoTime(); + void beforeTask(TaskRunner p0); + void coordinatorNotify(TaskRunner p0); + void coordinatorWait(TaskRunner p0, long p1); + void execute(Runnable p0); + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/Exchange.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/Exchange.java new file mode 100644 index 00000000000..3a3ea6f2997 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/Exchange.java @@ -0,0 +1,44 @@ +// Generated automatically from okhttp3.internal.connection.Exchange for testing purposes + +package okhttp3.internal.connection; + +import java.io.IOException; +import okhttp3.EventListener; +import okhttp3.Headers; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okhttp3.internal.connection.ExchangeFinder; +import okhttp3.internal.connection.RealCall; +import okhttp3.internal.connection.RealConnection; +import okhttp3.internal.http.ExchangeCodec; +import okhttp3.internal.ws.RealWebSocket; +import okio.Sink; + +public class Exchange +{ + protected Exchange() {} + public Exchange(RealCall p0, EventListener p1, ExchangeFinder p2, ExchangeCodec p3){} + public final E bodyComplete(long p0, boolean p1, boolean p2, E p3){ return null; } + public final EventListener getEventListener$okhttp(){ return null; } + public final ExchangeFinder getFinder$okhttp(){ return null; } + public final Headers trailers(){ return null; } + public final RealCall getCall$okhttp(){ return null; } + public final RealConnection getConnection$okhttp(){ return null; } + public final RealWebSocket.Streams newWebSocketStreams(){ return null; } + public final Response.Builder readResponseHeaders(boolean p0){ return null; } + public final ResponseBody openResponseBody(Response p0){ return null; } + public final Sink createRequestBody(Request p0, boolean p1){ return null; } + public final boolean isCoalescedConnection$okhttp(){ return false; } + public final boolean isDuplex$okhttp(){ return false; } + public final void cancel(){} + public final void detachWithViolence(){} + public final void finishRequest(){} + public final void flushRequest(){} + public final void noNewExchangesOnConnection(){} + public final void noRequestBody(){} + public final void responseHeadersEnd(Response p0){} + public final void responseHeadersStart(){} + public final void webSocketUpgradeFailed(){} + public final void writeRequestHeaders(Request p0){} +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/ExchangeFinder.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/ExchangeFinder.java new file mode 100644 index 00000000000..5565a5d71f5 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/ExchangeFinder.java @@ -0,0 +1,24 @@ +// Generated automatically from okhttp3.internal.connection.ExchangeFinder for testing purposes + +package okhttp3.internal.connection; + +import java.io.IOException; +import okhttp3.Address; +import okhttp3.EventListener; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.internal.connection.RealCall; +import okhttp3.internal.connection.RealConnectionPool; +import okhttp3.internal.http.ExchangeCodec; +import okhttp3.internal.http.RealInterceptorChain; + +public class ExchangeFinder +{ + protected ExchangeFinder() {} + public ExchangeFinder(RealConnectionPool p0, Address p1, RealCall p2, EventListener p3){} + public final Address getAddress$okhttp(){ return null; } + public final ExchangeCodec find(OkHttpClient p0, RealInterceptorChain p1){ return null; } + public final boolean retryAfterFailure(){ return false; } + public final boolean sameHostAndPort(HttpUrl p0){ return false; } + public final void trackFailure(IOException p0){} +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealCall.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealCall.java new file mode 100644 index 00000000000..82556dc96b6 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealCall.java @@ -0,0 +1,63 @@ +// Generated automatically from okhttp3.internal.connection.RealCall for testing purposes + +package okhttp3.internal.connection; + +import java.io.IOException; +import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicInteger; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.EventListener; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.internal.connection.Exchange; +import okhttp3.internal.connection.RealConnection; +import okhttp3.internal.http.RealInterceptorChain; +import okio.AsyncTimeout; + +public class RealCall implements Call +{ + protected RealCall() {} + public AsyncTimeout timeout(){ return null; } + public RealCall clone(){ return null; } + public RealCall(OkHttpClient p0, Request p1, boolean p2){} + public Request request(){ return null; } + public Response execute(){ return null; } + public boolean isCanceled(){ return false; } + public boolean isExecuted(){ return false; } + public class AsyncCall implements Runnable + { + protected AsyncCall() {} + public AsyncCall(Callback p0){} + public final AtomicInteger getCallsPerHost(){ return null; } + public final RealCall getCall(){ return null; } + public final Request getRequest(){ return null; } + public final String getHost(){ return null; } + public final void executeOn(ExecutorService p0){} + public final void reuseCallsPerHostFrom(RealCall.AsyncCall p0){} + public void run(){} + } + public final E messageDone$okhttp(Exchange p0, boolean p1, boolean p2, E p3){ return null; } + public final EventListener getEventListener$okhttp(){ return null; } + public final Exchange getInterceptorScopedExchange$okhttp(){ return null; } + public final Exchange initExchange$okhttp(RealInterceptorChain p0){ return null; } + public final IOException noMoreExchanges$okhttp(IOException p0){ return null; } + public final OkHttpClient getClient(){ return null; } + public final RealConnection getConnection(){ return null; } + public final RealConnection getConnectionToCancel(){ return null; } + public final Request getOriginalRequest(){ return null; } + public final Response getResponseWithInterceptorChain$okhttp(){ return null; } + public final Socket releaseConnectionNoEvents$okhttp(){ return null; } + public final String redactedUrl$okhttp(){ return null; } + public final boolean getForWebSocket(){ return false; } + public final boolean retryAfterFailure(){ return false; } + public final void acquireConnectionNoEvents(RealConnection p0){} + public final void enterNetworkInterceptorExchange(Request p0, boolean p1){} + public final void exitNetworkInterceptorExchange$okhttp(boolean p0){} + public final void setConnectionToCancel(RealConnection p0){} + public final void timeoutEarlyExit(){} + public void cancel(){} + public void enqueue(Callback p0){} +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealConnection.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealConnection.java new file mode 100644 index 00000000000..a45566bf0cc --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealConnection.java @@ -0,0 +1,65 @@ +// Generated automatically from okhttp3.internal.connection.RealConnection for testing purposes + +package okhttp3.internal.connection; + +import java.io.IOException; +import java.lang.ref.Reference; +import java.net.Socket; +import java.util.List; +import okhttp3.Address; +import okhttp3.Call; +import okhttp3.Connection; +import okhttp3.EventListener; +import okhttp3.Handshake; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okhttp3.Route; +import okhttp3.internal.connection.Exchange; +import okhttp3.internal.connection.RealCall; +import okhttp3.internal.connection.RealConnectionPool; +import okhttp3.internal.http.ExchangeCodec; +import okhttp3.internal.http.RealInterceptorChain; +import okhttp3.internal.http2.Http2Connection; +import okhttp3.internal.http2.Http2Stream; +import okhttp3.internal.http2.Settings; +import okhttp3.internal.ws.RealWebSocket; + +public class RealConnection extends Http2Connection.Listener implements Connection +{ + protected RealConnection() {} + public Handshake handshake(){ return null; } + public Protocol protocol(){ return null; } + public RealConnection(RealConnectionPool p0, Route p1){} + public Route route(){ return null; } + public Socket socket(){ return null; } + public String toString(){ return null; } + public final ExchangeCodec newCodec$okhttp(OkHttpClient p0, RealInterceptorChain p1){ return null; } + public final List> getCalls(){ return null; } + public final RealConnectionPool getConnectionPool(){ return null; } + public final RealWebSocket.Streams newWebSocketStreams$okhttp(Exchange p0){ return null; } + public final boolean getNoNewExchanges(){ return false; } + public final boolean isEligible$okhttp(Address p0, List p1){ return false; } + public final boolean isHealthy(boolean p0){ return false; } + public final boolean isMultiplexed$okhttp(){ return false; } + public final int getRouteFailureCount$okhttp(){ return 0; } + public final long getIdleAtNs$okhttp(){ return 0; } + public final void cancel(){} + public final void connect(int p0, int p1, int p2, int p3, boolean p4, Call p5, EventListener p6){} + public final void connectFailed$okhttp(OkHttpClient p0, Route p1, IOException p2){} + public final void incrementSuccessCount$okhttp(){} + public final void noCoalescedConnections$okhttp(){} + public final void noNewExchanges$okhttp(){} + public final void setIdleAtNs$okhttp(long p0){} + public final void setNoNewExchanges(boolean p0){} + public final void setRouteFailureCount$okhttp(int p0){} + public final void trackFailure$okhttp(RealCall p0, IOException p1){} + public static RealConnection.Companion Companion = null; + public static long IDLE_CONNECTION_HEALTHY_NS = 0; + public void onSettings(Http2Connection p0, Settings p1){} + public void onStream(Http2Stream p0){} + static public class Companion + { + protected Companion() {} + public final RealConnection newTestConnection(RealConnectionPool p0, Route p1, Socket p2, long p3){ return null; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealConnectionPool.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealConnectionPool.java new file mode 100644 index 00000000000..ea2fe9d1db5 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RealConnectionPool.java @@ -0,0 +1,31 @@ +// Generated automatically from okhttp3.internal.connection.RealConnectionPool for testing purposes + +package okhttp3.internal.connection; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import okhttp3.Address; +import okhttp3.ConnectionPool; +import okhttp3.Route; +import okhttp3.internal.concurrent.TaskRunner; +import okhttp3.internal.connection.RealCall; +import okhttp3.internal.connection.RealConnection; + +public class RealConnectionPool +{ + protected RealConnectionPool() {} + public RealConnectionPool(TaskRunner p0, int p1, long p2, TimeUnit p3){} + public final boolean callAcquirePooledConnection(Address p0, RealCall p1, List p2, boolean p3){ return false; } + public final boolean connectionBecameIdle(RealConnection p0){ return false; } + public final int connectionCount(){ return 0; } + public final int idleConnectionCount(){ return 0; } + public final long cleanup(long p0){ return 0; } + public final void evictAll(){} + public final void put(RealConnection p0){} + public static RealConnectionPool.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final RealConnectionPool get(ConnectionPool p0){ return null; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RouteDatabase.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RouteDatabase.java new file mode 100644 index 00000000000..089718b9417 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/connection/RouteDatabase.java @@ -0,0 +1,13 @@ +// Generated automatically from okhttp3.internal.connection.RouteDatabase for testing purposes + +package okhttp3.internal.connection; + +import okhttp3.Route; + +public class RouteDatabase +{ + public RouteDatabase(){} + public final boolean shouldPostpone(Route p0){ return false; } + public final void connected(Route p0){} + public final void failed(Route p0){} +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http/ExchangeCodec.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http/ExchangeCodec.java new file mode 100644 index 00000000000..209e0207e60 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http/ExchangeCodec.java @@ -0,0 +1,31 @@ +// Generated automatically from okhttp3.internal.http.ExchangeCodec for testing purposes + +package okhttp3.internal.http; + +import okhttp3.Headers; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.internal.connection.RealConnection; +import okio.Sink; +import okio.Source; + +public interface ExchangeCodec +{ + Headers trailers(); + RealConnection getConnection(); + Response.Builder readResponseHeaders(boolean p0); + Sink createRequestBody(Request p0, long p1); + Source openResponseBodySource(Response p0); + long reportedContentLength(Response p0); + static ExchangeCodec.Companion Companion = null; + static int DISCARD_STREAM_TIMEOUT_MILLIS = 0; + static public class Companion + { + protected Companion() {} + public static int DISCARD_STREAM_TIMEOUT_MILLIS = 0; + } + void cancel(); + void finishRequest(); + void flushRequest(); + void writeRequestHeaders(Request p0); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http/RealInterceptorChain.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http/RealInterceptorChain.java new file mode 100644 index 00000000000..0e1ce474afc --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http/RealInterceptorChain.java @@ -0,0 +1,36 @@ +// Generated automatically from okhttp3.internal.http.RealInterceptorChain for testing purposes + +package okhttp3.internal.http; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import okhttp3.Call; +import okhttp3.Connection; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.internal.connection.Exchange; +import okhttp3.internal.connection.RealCall; + +public class RealInterceptorChain implements Interceptor.Chain +{ + protected RealInterceptorChain() {} + public Call call(){ return null; } + public Connection connection(){ return null; } + public Interceptor.Chain withConnectTimeout(int p0, TimeUnit p1){ return null; } + public Interceptor.Chain withReadTimeout(int p0, TimeUnit p1){ return null; } + public Interceptor.Chain withWriteTimeout(int p0, TimeUnit p1){ return null; } + public RealInterceptorChain(RealCall p0, List p1, int p2, Exchange p3, Request p4, int p5, int p6, int p7){} + public Request request(){ return null; } + public Response proceed(Request p0){ return null; } + public final Exchange getExchange$okhttp(){ return null; } + public final RealCall getCall$okhttp(){ return null; } + public final RealInterceptorChain copy$okhttp(int p0, Exchange p1, Request p2, int p3, int p4, int p5){ return null; } + public final Request getRequest$okhttp(){ return null; } + public final int getConnectTimeoutMillis$okhttp(){ return 0; } + public final int getReadTimeoutMillis$okhttp(){ return 0; } + public final int getWriteTimeoutMillis$okhttp(){ return 0; } + public int connectTimeoutMillis(){ return 0; } + public int readTimeoutMillis(){ return 0; } + public int writeTimeoutMillis(){ return 0; } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/ErrorCode.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/ErrorCode.java new file mode 100644 index 00000000000..e45e320f54f --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/ErrorCode.java @@ -0,0 +1,17 @@ +// Generated automatically from okhttp3.internal.http2.ErrorCode for testing purposes + +package okhttp3.internal.http2; + + +public enum ErrorCode +{ + CANCEL, COMPRESSION_ERROR, CONNECT_ERROR, ENHANCE_YOUR_CALM, FLOW_CONTROL_ERROR, FRAME_SIZE_ERROR, HTTP_1_1_REQUIRED, INADEQUATE_SECURITY, INTERNAL_ERROR, NO_ERROR, PROTOCOL_ERROR, REFUSED_STREAM, SETTINGS_TIMEOUT, STREAM_CLOSED; + private ErrorCode() {} + public final int getHttpCode(){ return 0; } + public static ErrorCode.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final ErrorCode fromHttp2(int p0){ return null; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Header.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Header.java new file mode 100644 index 00000000000..dc4013f5be7 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Header.java @@ -0,0 +1,38 @@ +// Generated automatically from okhttp3.internal.http2.Header for testing purposes + +package okhttp3.internal.http2; + +import okio.ByteString; + +public class Header +{ + protected Header() {} + public Header(ByteString p0, ByteString p1){} + public Header(ByteString p0, String p1){} + public Header(String p0, String p1){} + public String toString(){ return null; } + public boolean equals(Object p0){ return false; } + public final ByteString component1(){ return null; } + public final ByteString component2(){ return null; } + public final ByteString name = null; + public final ByteString value = null; + public final Header copy(ByteString p0, ByteString p1){ return null; } + public final int hpackSize = 0; + public int hashCode(){ return 0; } + public static ByteString PSEUDO_PREFIX = null; + public static ByteString RESPONSE_STATUS = null; + public static ByteString TARGET_AUTHORITY = null; + public static ByteString TARGET_METHOD = null; + public static ByteString TARGET_PATH = null; + public static ByteString TARGET_SCHEME = null; + public static Header.Companion Companion = null; + public static String RESPONSE_STATUS_UTF8 = null; + public static String TARGET_AUTHORITY_UTF8 = null; + public static String TARGET_METHOD_UTF8 = null; + public static String TARGET_PATH_UTF8 = null; + public static String TARGET_SCHEME_UTF8 = null; + static public class Companion + { + protected Companion() {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Hpack.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Hpack.java new file mode 100644 index 00000000000..8c688bb64f3 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Hpack.java @@ -0,0 +1,34 @@ +// Generated automatically from okhttp3.internal.http2.Hpack for testing purposes + +package okhttp3.internal.http2; + +import java.util.List; +import java.util.Map; +import okhttp3.internal.http2.Header; +import okio.Buffer; +import okio.ByteString; + +public class Hpack +{ + protected Hpack() {} + public final ByteString checkLowercase(ByteString p0){ return null; } + public final Header[] getSTATIC_HEADER_TABLE(){ return null; } + public final Map getNAME_TO_FIRST_INDEX(){ return null; } + public static Hpack INSTANCE = null; + static public class Writer + { + protected Writer() {} + public Header[] dynamicTable = null; + public Writer(Buffer p0){} + public Writer(int p0, Buffer p1){} + public Writer(int p0, boolean p1, Buffer p2){} + public final void resizeHeaderTable(int p0){} + public final void writeByteString(ByteString p0){} + public final void writeHeaders(List
    p0){} + public final void writeInt(int p0, int p1, int p2){} + public int dynamicTableByteCount = 0; + public int headerCount = 0; + public int headerTableSizeSetting = 0; + public int maxDynamicTableByteCount = 0; + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Connection.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Connection.java new file mode 100644 index 00000000000..8e7b605f498 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Connection.java @@ -0,0 +1,153 @@ +// Generated automatically from okhttp3.internal.http2.Http2Connection for testing purposes + +package okhttp3.internal.http2; + +import java.io.Closeable; +import java.io.IOException; +import java.net.Socket; +import java.util.List; +import java.util.Map; +import kotlin.Unit; +import kotlin.jvm.functions.Function0; +import okhttp3.internal.concurrent.TaskRunner; +import okhttp3.internal.http2.ErrorCode; +import okhttp3.internal.http2.Header; +import okhttp3.internal.http2.Http2Reader; +import okhttp3.internal.http2.Http2Stream; +import okhttp3.internal.http2.Http2Writer; +import okhttp3.internal.http2.PushObserver; +import okhttp3.internal.http2.Settings; +import okio.Buffer; +import okio.BufferedSink; +import okio.BufferedSource; +import okio.ByteString; + +public class Http2Connection implements Closeable +{ + protected Http2Connection() {} + abstract static public class Listener + { + public Listener(){} + public abstract void onStream(Http2Stream p0); + public static Http2Connection.Listener REFUSE_INCOMING_STREAMS = null; + public static Http2Connection.Listener.Companion Companion = null; + public void onSettings(Http2Connection p0, Settings p1){} + static public class Companion + { + protected Companion() {} + } + } + public Http2Connection(Http2Connection.Builder p0){} + public class ReaderRunnable implements Function0, Http2Reader.Handler + { + protected ReaderRunnable() {} + public ReaderRunnable(Http2Reader p0){} + public final Http2Reader getReader$okhttp(){ return null; } + public final void applyAndAckSettings(boolean p0, Settings p1){} + public void ackSettings(){} + public void alternateService(int p0, String p1, ByteString p2, String p3, int p4, long p5){} + public void data(boolean p0, int p1, BufferedSource p2, int p3){} + public void goAway(int p0, ErrorCode p1, ByteString p2){} + public void headers(boolean p0, int p1, int p2, List
    p3){} + public Void invoke(){ return null; } + public void ping(boolean p0, int p1, int p2){} + public void priority(int p0, int p1, int p2, boolean p3){} + public void pushPromise(int p0, int p1, List
    p2){} + public void rstStream(int p0, ErrorCode p1){} + public void settings(boolean p0, Settings p1){} + public void windowUpdate(int p0, long p1){} + } + public final Http2Connection.Listener getListener$okhttp(){ return null; } + public final Http2Connection.ReaderRunnable getReaderRunnable(){ return null; } + public final Http2Stream getStream(int p0){ return null; } + public final Http2Stream newStream(List
    p0, boolean p1){ return null; } + public final Http2Stream pushStream(int p0, List
    p1, boolean p2){ return null; } + public final Http2Stream removeStream$okhttp(int p0){ return null; } + public final Http2Writer getWriter(){ return null; } + public final Map getStreams$okhttp(){ return null; } + public final Settings getOkHttpSettings(){ return null; } + public final Settings getPeerSettings(){ return null; } + public final Socket getSocket$okhttp(){ return null; } + public final String getConnectionName$okhttp(){ return null; } + public final boolean getClient$okhttp(){ return false; } + public final boolean isHealthy(long p0){ return false; } + public final boolean pushedStream$okhttp(int p0){ return false; } + public final int getLastGoodStreamId$okhttp(){ return 0; } + public final int getNextStreamId$okhttp(){ return 0; } + public final int openStreamCount(){ return 0; } + public final long getReadBytesAcknowledged(){ return 0; } + public final long getReadBytesTotal(){ return 0; } + public final long getWriteBytesMaximum(){ return 0; } + public final long getWriteBytesTotal(){ return 0; } + public final void awaitPong(){} + public final void close$okhttp(ErrorCode p0, ErrorCode p1, IOException p2){} + public final void flush(){} + public final void pushDataLater$okhttp(int p0, BufferedSource p1, int p2, boolean p3){} + public final void pushHeadersLater$okhttp(int p0, List
    p1, boolean p2){} + public final void pushRequestLater$okhttp(int p0, List
    p1){} + public final void pushResetLater$okhttp(int p0, ErrorCode p1){} + public final void sendDegradedPingLater$okhttp(){} + public final void setLastGoodStreamId$okhttp(int p0){} + public final void setNextStreamId$okhttp(int p0){} + public final void setPeerSettings(Settings p0){} + public final void setSettings(Settings p0){} + public final void shutdown(ErrorCode p0){} + public final void start(){} + public final void start(boolean p0){} + public final void start(boolean p0, TaskRunner p1){} + public final void updateConnectionFlowControl$okhttp(long p0){} + public final void writeData(int p0, boolean p1, Buffer p2, long p3){} + public final void writeHeaders$okhttp(int p0, boolean p1, List
    p2){} + public final void writePing(){} + public final void writePing(boolean p0, int p1, int p2){} + public final void writePingAndAwaitPong(){} + public final void writeSynReset$okhttp(int p0, ErrorCode p1){} + public final void writeSynResetLater$okhttp(int p0, ErrorCode p1){} + public final void writeWindowUpdateLater$okhttp(int p0, long p1){} + public static Http2Connection.Companion Companion = null; + public static int AWAIT_PING = 0; + public static int DEGRADED_PING = 0; + public static int DEGRADED_PONG_TIMEOUT_NS = 0; + public static int INTERVAL_PING = 0; + public static int OKHTTP_CLIENT_WINDOW_SIZE = 0; + public void close(){} + static public class Builder + { + protected Builder() {} + public BufferedSink sink = null; + public BufferedSource source = null; + public Builder(boolean p0, TaskRunner p1){} + public Socket socket = null; + public String connectionName = null; + public final BufferedSink getSink$okhttp(){ return null; } + public final BufferedSource getSource$okhttp(){ return null; } + public final Http2Connection build(){ return null; } + public final Http2Connection.Builder listener(Http2Connection.Listener p0){ return null; } + public final Http2Connection.Builder pingIntervalMillis(int p0){ return null; } + public final Http2Connection.Builder pushObserver(PushObserver p0){ return null; } + public final Http2Connection.Builder socket(Socket p0){ return null; } + public final Http2Connection.Builder socket(Socket p0, String p1){ return null; } + public final Http2Connection.Builder socket(Socket p0, String p1, BufferedSource p2){ return null; } + public final Http2Connection.Builder socket(Socket p0, String p1, BufferedSource p2, BufferedSink p3){ return null; } + public final Http2Connection.Listener getListener$okhttp(){ return null; } + public final PushObserver getPushObserver$okhttp(){ return null; } + public final Socket getSocket$okhttp(){ return null; } + public final String getConnectionName$okhttp(){ return null; } + public final TaskRunner getTaskRunner$okhttp(){ return null; } + public final boolean getClient$okhttp(){ return false; } + public final int getPingIntervalMillis$okhttp(){ return 0; } + public final void setClient$okhttp(boolean p0){} + public final void setConnectionName$okhttp(String p0){} + public final void setListener$okhttp(Http2Connection.Listener p0){} + public final void setPingIntervalMillis$okhttp(int p0){} + public final void setPushObserver$okhttp(PushObserver p0){} + public final void setSink$okhttp(BufferedSink p0){} + public final void setSocket$okhttp(Socket p0){} + public final void setSource$okhttp(BufferedSource p0){} + } + static public class Companion + { + protected Companion() {} + public final Settings getDEFAULT_SETTINGS(){ return null; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Reader.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Reader.java new file mode 100644 index 00000000000..b6aedef6d52 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Reader.java @@ -0,0 +1,42 @@ +// Generated automatically from okhttp3.internal.http2.Http2Reader for testing purposes + +package okhttp3.internal.http2; + +import java.io.Closeable; +import java.util.List; +import java.util.logging.Logger; +import okhttp3.internal.http2.ErrorCode; +import okhttp3.internal.http2.Header; +import okhttp3.internal.http2.Settings; +import okio.BufferedSource; +import okio.ByteString; + +public class Http2Reader implements Closeable +{ + protected Http2Reader() {} + public Http2Reader(BufferedSource p0, boolean p1){} + public final boolean nextFrame(boolean p0, Http2Reader.Handler p1){ return false; } + public final void readConnectionPreface(Http2Reader.Handler p0){} + public static Http2Reader.Companion Companion = null; + public void close(){} + static public class Companion + { + protected Companion() {} + public final Logger getLogger(){ return null; } + public final int lengthWithoutPadding(int p0, int p1, int p2){ return 0; } + } + static public interface Handler + { + void ackSettings(); + void alternateService(int p0, String p1, ByteString p2, String p3, int p4, long p5); + void data(boolean p0, int p1, BufferedSource p2, int p3); + void goAway(int p0, ErrorCode p1, ByteString p2); + void headers(boolean p0, int p1, int p2, List
    p3); + void ping(boolean p0, int p1, int p2); + void priority(int p0, int p1, int p2, boolean p3); + void pushPromise(int p0, int p1, List
    p2); + void rstStream(int p0, ErrorCode p1); + void settings(boolean p0, Settings p1); + void windowUpdate(int p0, long p1); + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Stream.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Stream.java new file mode 100644 index 00000000000..47b460bb385 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Stream.java @@ -0,0 +1,104 @@ +// Generated automatically from okhttp3.internal.http2.Http2Stream for testing purposes + +package okhttp3.internal.http2; + +import java.io.IOException; +import java.util.List; +import okhttp3.Headers; +import okhttp3.internal.http2.ErrorCode; +import okhttp3.internal.http2.Header; +import okhttp3.internal.http2.Http2Connection; +import okio.AsyncTimeout; +import okio.Buffer; +import okio.BufferedSource; +import okio.Sink; +import okio.Source; +import okio.Timeout; + +public class Http2Stream +{ + protected Http2Stream() {} + public Http2Stream(int p0, Http2Connection p1, boolean p2, boolean p3, Headers p4){} + public class FramingSink implements Sink + { + protected FramingSink() {} + public FramingSink(boolean p0){} + public Timeout timeout(){ return null; } + public final Headers getTrailers(){ return null; } + public final boolean getClosed(){ return false; } + public final boolean getFinished(){ return false; } + public final void setClosed(boolean p0){} + public final void setFinished(boolean p0){} + public final void setTrailers(Headers p0){} + public void close(){} + public void flush(){} + public void write(Buffer p0, long p1){} + } + public class FramingSource implements Source + { + protected FramingSource() {} + public FramingSource(long p0, boolean p1){} + public Timeout timeout(){ return null; } + public final Buffer getReadBuffer(){ return null; } + public final Buffer getReceiveBuffer(){ return null; } + public final Headers getTrailers(){ return null; } + public final boolean getClosed$okhttp(){ return false; } + public final boolean getFinished$okhttp(){ return false; } + public final void receive$okhttp(BufferedSource p0, long p1){} + public final void setClosed$okhttp(boolean p0){} + public final void setFinished$okhttp(boolean p0){} + public final void setTrailers(Headers p0){} + public long read(Buffer p0, long p1){ return 0; } + public void close(){} + } + public class StreamTimeout extends AsyncTimeout + { + protected IOException newTimeoutException(IOException p0){ return null; } + protected void timedOut(){} + public StreamTimeout(){} + public final void exitAndThrowIfTimedOut(){} + } + public final ErrorCode getErrorCode$okhttp(){ return null; } + public final Headers takeHeaders(){ return null; } + public final Headers trailers(){ return null; } + public final Http2Connection getConnection(){ return null; } + public final Http2Stream.FramingSink getSink$okhttp(){ return null; } + public final Http2Stream.FramingSource getSource$okhttp(){ return null; } + public final Http2Stream.StreamTimeout getReadTimeout$okhttp(){ return null; } + public final Http2Stream.StreamTimeout getWriteTimeout$okhttp(){ return null; } + public final IOException getErrorException$okhttp(){ return null; } + public final Sink getSink(){ return null; } + public final Source getSource(){ return null; } + public final Timeout readTimeout(){ return null; } + public final Timeout writeTimeout(){ return null; } + public final boolean isLocallyInitiated(){ return false; } + public final boolean isOpen(){ return false; } + public final int getId(){ return 0; } + public final long getReadBytesAcknowledged(){ return 0; } + public final long getReadBytesTotal(){ return 0; } + public final long getWriteBytesMaximum(){ return 0; } + public final long getWriteBytesTotal(){ return 0; } + public final void addBytesToWriteWindow(long p0){} + public final void cancelStreamIfNecessary$okhttp(){} + public final void checkOutNotClosed$okhttp(){} + public final void close(ErrorCode p0, IOException p1){} + public final void closeLater(ErrorCode p0){} + public final void enqueueTrailers(Headers p0){} + public final void receiveData(BufferedSource p0, int p1){} + public final void receiveHeaders(Headers p0, boolean p1){} + public final void receiveRstStream(ErrorCode p0){} + public final void setErrorCode$okhttp(ErrorCode p0){} + public final void setErrorException$okhttp(IOException p0){} + public final void setReadBytesAcknowledged$okhttp(long p0){} + public final void setReadBytesTotal$okhttp(long p0){} + public final void setWriteBytesMaximum$okhttp(long p0){} + public final void setWriteBytesTotal$okhttp(long p0){} + public final void waitForIo$okhttp(){} + public final void writeHeaders(List
    p0, boolean p1, boolean p2){} + public static Http2Stream.Companion Companion = null; + public static long EMIT_BUFFER_SIZE = 0; + static public class Companion + { + protected Companion() {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Writer.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Writer.java new file mode 100644 index 00000000000..c05713f93c2 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Http2Writer.java @@ -0,0 +1,39 @@ +// Generated automatically from okhttp3.internal.http2.Http2Writer for testing purposes + +package okhttp3.internal.http2; + +import java.io.Closeable; +import java.util.List; +import okhttp3.internal.http2.ErrorCode; +import okhttp3.internal.http2.Header; +import okhttp3.internal.http2.Hpack; +import okhttp3.internal.http2.Settings; +import okio.Buffer; +import okio.BufferedSink; + +public class Http2Writer implements Closeable +{ + protected Http2Writer() {} + public Http2Writer(BufferedSink p0, boolean p1){} + public final Hpack.Writer getHpackWriter(){ return null; } + public final int maxDataLength(){ return 0; } + public final void applyAndAckSettings(Settings p0){} + public final void connectionPreface(){} + public final void data(boolean p0, int p1, Buffer p2, int p3){} + public final void dataFrame(int p0, int p1, Buffer p2, int p3){} + public final void flush(){} + public final void frameHeader(int p0, int p1, int p2, int p3){} + public final void goAway(int p0, ErrorCode p1, byte[] p2){} + public final void headers(boolean p0, int p1, List
    p2){} + public final void ping(boolean p0, int p1, int p2){} + public final void pushPromise(int p0, int p1, List
    p2){} + public final void rstStream(int p0, ErrorCode p1){} + public final void settings(Settings p0){} + public final void windowUpdate(int p0, long p1){} + public static Http2Writer.Companion Companion = null; + public void close(){} + static public class Companion + { + protected Companion() {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/PushObserver.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/PushObserver.java new file mode 100644 index 00000000000..a4d88297d2a --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/PushObserver.java @@ -0,0 +1,22 @@ +// Generated automatically from okhttp3.internal.http2.PushObserver for testing purposes + +package okhttp3.internal.http2; + +import java.util.List; +import okhttp3.internal.http2.ErrorCode; +import okhttp3.internal.http2.Header; +import okio.BufferedSource; + +public interface PushObserver +{ + boolean onData(int p0, BufferedSource p1, int p2, boolean p3); + boolean onHeaders(int p0, List
    p1, boolean p2); + boolean onRequest(int p0, List
    p1); + static PushObserver CANCEL = null; + static PushObserver.Companion Companion = null; + static public class Companion + { + protected Companion() {} + } + void onReset(int p0, ErrorCode p1); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Settings.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Settings.java new file mode 100644 index 00000000000..7078c1ad1d1 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/http2/Settings.java @@ -0,0 +1,34 @@ +// Generated automatically from okhttp3.internal.http2.Settings for testing purposes + +package okhttp3.internal.http2; + + +public class Settings +{ + public Settings(){} + public final Settings set(int p0, int p1){ return null; } + public final boolean getEnablePush(boolean p0){ return false; } + public final boolean isSet(int p0){ return false; } + public final int get(int p0){ return 0; } + public final int getHeaderTableSize(){ return 0; } + public final int getInitialWindowSize(){ return 0; } + public final int getMaxConcurrentStreams(){ return 0; } + public final int getMaxFrameSize(int p0){ return 0; } + public final int getMaxHeaderListSize(int p0){ return 0; } + public final int size(){ return 0; } + public final void clear(){} + public final void merge(Settings p0){} + public static Settings.Companion Companion = null; + public static int COUNT = 0; + public static int DEFAULT_INITIAL_WINDOW_SIZE = 0; + public static int ENABLE_PUSH = 0; + public static int HEADER_TABLE_SIZE = 0; + public static int INITIAL_WINDOW_SIZE = 0; + public static int MAX_CONCURRENT_STREAMS = 0; + public static int MAX_FRAME_SIZE = 0; + public static int MAX_HEADER_LIST_SIZE = 0; + static public class Companion + { + protected Companion() {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/io/FileSystem.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/io/FileSystem.java new file mode 100644 index 00000000000..1967f0d99d8 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/io/FileSystem.java @@ -0,0 +1,25 @@ +// Generated automatically from okhttp3.internal.io.FileSystem for testing purposes + +package okhttp3.internal.io; + +import java.io.File; +import okio.Sink; +import okio.Source; + +public interface FileSystem +{ + Sink appendingSink(File p0); + Sink sink(File p0); + Source source(File p0); + boolean exists(File p0); + long size(File p0); + static FileSystem SYSTEM = null; + static FileSystem.Companion Companion = null; + static public class Companion + { + protected Companion() {} + } + void delete(File p0); + void deleteContents(File p0); + void rename(File p0, File p1); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/tls/CertificateChainCleaner.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/tls/CertificateChainCleaner.java new file mode 100644 index 00000000000..1ebaf1ee917 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/tls/CertificateChainCleaner.java @@ -0,0 +1,21 @@ +// Generated automatically from okhttp3.internal.tls.CertificateChainCleaner for testing purposes + +package okhttp3.internal.tls; + +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.List; +import javax.net.ssl.X509TrustManager; + +abstract public class CertificateChainCleaner +{ + public CertificateChainCleaner(){} + public abstract List clean(List p0, String p1); + public static CertificateChainCleaner.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final CertificateChainCleaner get(X509Certificate... p0){ return null; } + public final CertificateChainCleaner get(X509TrustManager p0){ return null; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/RealWebSocket.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/RealWebSocket.java new file mode 100644 index 00000000000..87457777e0b --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/RealWebSocket.java @@ -0,0 +1,66 @@ +// Generated automatically from okhttp3.internal.ws.RealWebSocket for testing purposes + +package okhttp3.internal.ws; + +import java.io.Closeable; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; +import okhttp3.internal.concurrent.TaskRunner; +import okhttp3.internal.connection.Exchange; +import okhttp3.internal.ws.WebSocketExtensions; +import okhttp3.internal.ws.WebSocketReader; +import okio.BufferedSink; +import okio.BufferedSource; +import okio.ByteString; + +public class RealWebSocket implements WebSocket, WebSocketReader.FrameCallback +{ + protected RealWebSocket() {} + abstract static public class Streams implements Closeable + { + protected Streams() {} + public Streams(boolean p0, BufferedSource p1, BufferedSink p2){} + public final BufferedSink getSink(){ return null; } + public final BufferedSource getSource(){ return null; } + public final boolean getClient(){ return false; } + } + public RealWebSocket(TaskRunner p0, Request p1, WebSocketListener p2, Random p3, long p4, WebSocketExtensions p5, long p6){} + public Request request(){ return null; } + public boolean close(int p0, String p1){ return false; } + public boolean send(ByteString p0){ return false; } + public boolean send(String p0){ return false; } + public final WebSocketListener getListener$okhttp(){ return null; } + public final boolean close(int p0, String p1, long p2){ return false; } + public final boolean pong(ByteString p0){ return false; } + public final boolean processNextFrame(){ return false; } + public final boolean writeOneFrame$okhttp(){ return false; } + public final int receivedPingCount(){ return 0; } + public final int receivedPongCount(){ return 0; } + public final int sentPingCount(){ return 0; } + public final void awaitTermination(long p0, TimeUnit p1){} + public final void checkUpgradeSuccess$okhttp(Response p0, Exchange p1){} + public final void connect(OkHttpClient p0){} + public final void failWebSocket(Exception p0, Response p1){} + public final void initReaderAndWriter(String p0, RealWebSocket.Streams p1){} + public final void loopReader(){} + public final void tearDown(){} + public final void writePingFrame$okhttp(){} + public long queueSize(){ return 0; } + public static RealWebSocket.Companion Companion = null; + public static long DEFAULT_MINIMUM_DEFLATE_SIZE = 0; + public void cancel(){} + public void onReadClose(int p0, String p1){} + public void onReadMessage(ByteString p0){} + public void onReadMessage(String p0){} + public void onReadPing(ByteString p0){} + public void onReadPong(ByteString p0){} + static public class Companion + { + protected Companion() {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/WebSocketExtensions.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/WebSocketExtensions.java new file mode 100644 index 00000000000..f2e8945f548 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/WebSocketExtensions.java @@ -0,0 +1,34 @@ +// Generated automatically from okhttp3.internal.ws.WebSocketExtensions for testing purposes + +package okhttp3.internal.ws; + +import okhttp3.Headers; + +public class WebSocketExtensions +{ + public String toString(){ return null; } + public WebSocketExtensions(){} + public WebSocketExtensions(boolean p0, Integer p1, boolean p2, Integer p3, boolean p4, boolean p5){} + public boolean equals(Object p0){ return false; } + public final Integer clientMaxWindowBits = null; + public final Integer component2(){ return null; } + public final Integer component4(){ return null; } + public final Integer serverMaxWindowBits = null; + public final WebSocketExtensions copy(boolean p0, Integer p1, boolean p2, Integer p3, boolean p4, boolean p5){ return null; } + public final boolean clientNoContextTakeover = false; + public final boolean component1(){ return false; } + public final boolean component3(){ return false; } + public final boolean component5(){ return false; } + public final boolean component6(){ return false; } + public final boolean noContextTakeover(boolean p0){ return false; } + public final boolean perMessageDeflate = false; + public final boolean serverNoContextTakeover = false; + public final boolean unknownValues = false; + public int hashCode(){ return 0; } + public static WebSocketExtensions.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final WebSocketExtensions parse(Headers p0){ return null; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/WebSocketReader.java b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/WebSocketReader.java new file mode 100644 index 00000000000..6dfdd507843 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okhttp3/internal/ws/WebSocketReader.java @@ -0,0 +1,24 @@ +// Generated automatically from okhttp3.internal.ws.WebSocketReader for testing purposes + +package okhttp3.internal.ws; + +import java.io.Closeable; +import okio.BufferedSource; +import okio.ByteString; + +public class WebSocketReader implements Closeable +{ + protected WebSocketReader() {} + public WebSocketReader(boolean p0, BufferedSource p1, WebSocketReader.FrameCallback p2, boolean p3, boolean p4){} + public final BufferedSource getSource(){ return null; } + public final void processNextFrame(){} + public void close(){} + static public interface FrameCallback + { + void onReadClose(int p0, String p1); + void onReadMessage(ByteString p0); + void onReadMessage(String p0); + void onReadPing(ByteString p0); + void onReadPong(ByteString p0); + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okio/AsyncTimeout.java b/java/ql/test/stubs/okhttp-4.9.3/okio/AsyncTimeout.java new file mode 100644 index 00000000000..2f341cfac25 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okio/AsyncTimeout.java @@ -0,0 +1,28 @@ +// Generated automatically from okio.AsyncTimeout for testing purposes + +package okio; + +import java.io.IOException; +import kotlin.jvm.functions.Function0; +import okio.Sink; +import okio.Source; +import okio.Timeout; + +public class AsyncTimeout extends Timeout +{ + protected IOException newTimeoutException(IOException p0){ return null; } + protected void timedOut(){} + public AsyncTimeout(){} + public final T withTimeout(Function0 p0){ return null; } + public final IOException access$newTimeoutException(IOException p0){ return null; } + public final Sink sink(Sink p0){ return null; } + public final Source source(Source p0){ return null; } + public final boolean exit(){ return false; } + public final void enter(){} + public static AsyncTimeout.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final AsyncTimeout awaitTimeout$okio(){ return null; } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okio/Buffer.java b/java/ql/test/stubs/okhttp-4.9.3/okio/Buffer.java new file mode 100644 index 00000000000..3a270f5e9eb --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okio/Buffer.java @@ -0,0 +1,469 @@ +// Generated automatically from okio.Buffer for testing purposes + +package okio; + +import java.io.Closeable; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.ByteChannel; +import java.nio.charset.Charset; +import okio.BufferedSink; +import okio.BufferedSource; +import okio.ByteString; +import okio.Options; +import okio.Segment; +import okio.Sink; +import okio.Source; +import okio.Timeout; + +public class Buffer implements BufferedSink, BufferedSource, ByteChannel, Cloneable { + public Buffer buffer() { + return null; + } + + public Buffer clone() { + return null; + } + + public Buffer emit() { + return null; + } + + public Buffer emitCompleteSegments() { + return null; + } + + public Buffer getBuffer() { + return null; + } + + public Buffer write(ByteString p0) { + return null; + } + + public Buffer write(ByteString p0, int p1, int p2) { + return null; + } + + public Buffer write(Source p0, long p1) { + return null; + } + + public Buffer write(byte[] p0) { + return null; + } + + public Buffer write(byte[] p0, int p1, int p2) { + return null; + } + + public Buffer writeByte(int p0) { + return null; + } + + public Buffer writeDecimalLong(long p0) { + return null; + } + + public Buffer writeHexadecimalUnsignedLong(long p0) { + return null; + } + + public Buffer writeInt(int p0) { + return null; + } + + public Buffer writeIntLe(int p0) { + return null; + } + + public Buffer writeLong(long p0) { + return null; + } + + public Buffer writeLongLe(long p0) { + return null; + } + + public Buffer writeShort(int p0) { + return null; + } + + public Buffer writeShortLe(int p0) { + return null; + } + + public Buffer writeString(String p0, Charset p1) { + return null; + } + + public Buffer writeString(String p0, int p1, int p2, Charset p3) { + return null; + } + + public Buffer writeUtf8(String p0) { + return null; + } + + public Buffer writeUtf8(String p0, int p1, int p2) { + return null; + } + + public Buffer writeUtf8CodePoint(int p0) { + return null; + } + + public Buffer() {} + + public BufferedSource peek() { + return null; + } + + public ByteString readByteString() { + return null; + } + + public ByteString readByteString(long p0) { + return null; + } + + public InputStream inputStream() { + return null; + } + + public OutputStream outputStream() { + return null; + } + + public Segment head = null; + + public String readString(Charset p0) { + return null; + } + + public String readString(long p0, Charset p1) { + return null; + } + + public String readUtf8() { + return null; + } + + public String readUtf8(long p0) { + return null; + } + + public String readUtf8Line() { + return null; + } + + public String readUtf8LineStrict() { + return null; + } + + public String readUtf8LineStrict(long p0) { + return null; + } + + public String toString() { + return null; + } + + public Timeout timeout() { + return null; + } + + public boolean equals(Object p0) { + return false; + } + + public boolean exhausted() { + return false; + } + + public boolean isOpen() { + return false; + } + + public boolean rangeEquals(long p0, ByteString p1) { + return false; + } + + public boolean rangeEquals(long p0, ByteString p1, int p2, int p3) { + return false; + } + + public boolean request(long p0) { + return false; + } + + public byte readByte() { + return 0; + } + + public byte[] readByteArray() { + return null; + } + + public byte[] readByteArray(long p0) { + return null; + } + + public final Buffer copy() { + return null; + } + + public final Buffer copyTo(Buffer p0, long p1) { + return null; + } + + public final Buffer copyTo(Buffer p0, long p1, long p2) { + return null; + } + + public final Buffer copyTo(OutputStream p0) { + return null; + } + + public final Buffer copyTo(OutputStream p0, long p1) { + return null; + } + + public final Buffer copyTo(OutputStream p0, long p1, long p2) { + return null; + } + + public final Buffer readFrom(InputStream p0) { + return null; + } + + public final Buffer readFrom(InputStream p0, long p1) { + return null; + } + + public final Buffer writeTo(OutputStream p0) { + return null; + } + + public final Buffer writeTo(OutputStream p0, long p1) { + return null; + } + + public final Buffer.UnsafeCursor readAndWriteUnsafe() { + return null; + } + + public final Buffer.UnsafeCursor readAndWriteUnsafe(Buffer.UnsafeCursor p0) { + return null; + } + + public final Buffer.UnsafeCursor readUnsafe() { + return null; + } + + public final Buffer.UnsafeCursor readUnsafe(Buffer.UnsafeCursor p0) { + return null; + } + + public final ByteString hmacSha1(ByteString p0) { + return null; + } + + public final ByteString hmacSha256(ByteString p0) { + return null; + } + + public final ByteString hmacSha512(ByteString p0) { + return null; + } + + public final ByteString md5() { + return null; + } + + public final ByteString sha1() { + return null; + } + + public final ByteString sha256() { + return null; + } + + public final ByteString sha512() { + return null; + } + + public final ByteString snapshot() { + return null; + } + + public final ByteString snapshot(int p0) { + return null; + } + + public final Segment writableSegment$okio(int p0) { + return null; + } + + public final byte getByte(long p0) { + return 0; + } + + public final long completeSegmentByteCount() { + return 0; + } + + public final long size() { + return 0; + } + + public final void clear() {} + + public final void setSize$okio(long p0) {} + + public int hashCode() { + return 0; + } + + public int read(ByteBuffer p0) { + return 0; + } + + public int read(byte[] p0) { + return 0; + } + + public int read(byte[] p0, int p1, int p2) { + return 0; + } + + public int readInt() { + return 0; + } + + public int readIntLe() { + return 0; + } + + public int readUtf8CodePoint() { + return 0; + } + + public int select(Options p0) { + return 0; + } + + public int write(ByteBuffer p0) { + return 0; + } + + public long indexOf(ByteString p0) { + return 0; + } + + public long indexOf(ByteString p0, long p1) { + return 0; + } + + public long indexOf(byte p0) { + return 0; + } + + public long indexOf(byte p0, long p1) { + return 0; + } + + public long indexOf(byte p0, long p1, long p2) { + return 0; + } + + public long indexOfElement(ByteString p0) { + return 0; + } + + public long indexOfElement(ByteString p0, long p1) { + return 0; + } + + public long read(Buffer p0, long p1) { + return 0; + } + + public long readAll(Sink p0) { + return 0; + } + + public long readDecimalLong() { + return 0; + } + + public long readHexadecimalUnsignedLong() { + return 0; + } + + public long readLong() { + return 0; + } + + public long readLongLe() { + return 0; + } + + public long writeAll(Source p0) { + return 0; + } + + public short readShort() { + return 0; + } + + public short readShortLe() { + return 0; + } + + public void close() {} + + public void flush() {} + + public void readFully(Buffer p0, long p1) {} + + public void readFully(byte[] p0) {} + + public void require(long p0) {} + + public void skip(long p0) {} + + public void write(Buffer p0, long p1) {} + + static public class UnsafeCursor implements Closeable { + public Buffer buffer = null; + + public UnsafeCursor() {} + + public boolean readWrite = false; + public byte[] data = null; + + public final int next() { + return 0; + } + + public final int seek(long p0) { + return 0; + } + + public final long expandBuffer(int p0) { + return 0; + } + + public final long resizeBuffer(long p0) { + return 0; + } + + public int end = 0; + public int start = 0; + public long offset = 0; + + public void close() {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okio/BufferedSink.java b/java/ql/test/stubs/okhttp-4.9.3/okio/BufferedSink.java new file mode 100644 index 00000000000..617924163a5 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okio/BufferedSink.java @@ -0,0 +1,41 @@ +// Generated automatically from okio.BufferedSink for testing purposes + +package okio; + +import java.io.OutputStream; +import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; +import okio.Buffer; +import okio.ByteString; +import okio.Sink; +import okio.Source; + +public interface BufferedSink extends Sink, WritableByteChannel +{ + Buffer buffer(); + Buffer getBuffer(); + BufferedSink emit(); + BufferedSink emitCompleteSegments(); + BufferedSink write(ByteString p0); + BufferedSink write(ByteString p0, int p1, int p2); + BufferedSink write(Source p0, long p1); + BufferedSink write(byte[] p0); + BufferedSink write(byte[] p0, int p1, int p2); + BufferedSink writeByte(int p0); + BufferedSink writeDecimalLong(long p0); + BufferedSink writeHexadecimalUnsignedLong(long p0); + BufferedSink writeInt(int p0); + BufferedSink writeIntLe(int p0); + BufferedSink writeLong(long p0); + BufferedSink writeLongLe(long p0); + BufferedSink writeShort(int p0); + BufferedSink writeShortLe(int p0); + BufferedSink writeString(String p0, Charset p1); + BufferedSink writeString(String p0, int p1, int p2, Charset p3); + BufferedSink writeUtf8(String p0); + BufferedSink writeUtf8(String p0, int p1, int p2); + BufferedSink writeUtf8CodePoint(int p0); + OutputStream outputStream(); + long writeAll(Source p0); + void flush(); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okio/BufferedSource.java b/java/ql/test/stubs/okhttp-4.9.3/okio/BufferedSource.java new file mode 100644 index 00000000000..fb16e1e8cf5 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okio/BufferedSource.java @@ -0,0 +1,60 @@ +// Generated automatically from okio.BufferedSource for testing purposes + +package okio; + +import java.io.InputStream; +import java.nio.channels.ReadableByteChannel; +import java.nio.charset.Charset; +import okio.Buffer; +import okio.ByteString; +import okio.Options; +import okio.Sink; +import okio.Source; + +public interface BufferedSource extends ReadableByteChannel, Source +{ + Buffer buffer(); + Buffer getBuffer(); + BufferedSource peek(); + ByteString readByteString(); + ByteString readByteString(long p0); + InputStream inputStream(); + String readString(Charset p0); + String readString(long p0, Charset p1); + String readUtf8(); + String readUtf8(long p0); + String readUtf8Line(); + String readUtf8LineStrict(); + String readUtf8LineStrict(long p0); + boolean exhausted(); + boolean rangeEquals(long p0, ByteString p1); + boolean rangeEquals(long p0, ByteString p1, int p2, int p3); + boolean request(long p0); + byte readByte(); + byte[] readByteArray(); + byte[] readByteArray(long p0); + int read(byte[] p0); + int read(byte[] p0, int p1, int p2); + int readInt(); + int readIntLe(); + int readUtf8CodePoint(); + int select(Options p0); + long indexOf(ByteString p0); + long indexOf(ByteString p0, long p1); + long indexOf(byte p0); + long indexOf(byte p0, long p1); + long indexOf(byte p0, long p1, long p2); + long indexOfElement(ByteString p0); + long indexOfElement(ByteString p0, long p1); + long readAll(Sink p0); + long readDecimalLong(); + long readHexadecimalUnsignedLong(); + long readLong(); + long readLongLe(); + short readShort(); + short readShortLe(); + void readFully(Buffer p0, long p1); + void readFully(byte[] p0); + void require(long p0); + void skip(long p0); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okio/ByteString.java b/java/ql/test/stubs/okhttp-4.9.3/okio/ByteString.java new file mode 100644 index 00000000000..2ac5fe9901a --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okio/ByteString.java @@ -0,0 +1,284 @@ +// Generated automatically from okio.ByteString for testing purposes + +package okio; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import okio.Buffer; + +public class ByteString implements Comparable, Serializable { + protected ByteString() {} + + public ByteBuffer asByteBuffer() { + return null; + } + + public ByteString digest$okio(String p0) { + return null; + } + + public ByteString hmac$okio(String p0, ByteString p1) { + return null; + } + + public ByteString hmacSha1(ByteString p0) { + return null; + } + + public ByteString hmacSha256(ByteString p0) { + return null; + } + + public ByteString hmacSha512(ByteString p0) { + return null; + } + + public ByteString md5() { + return null; + } + + public ByteString sha1() { + return null; + } + + public ByteString sha256() { + return null; + } + + public ByteString sha512() { + return null; + } + + public ByteString substring(int p0, int p1) { + return null; + } + + public ByteString toAsciiLowercase() { + return null; + } + + public ByteString toAsciiUppercase() { + return null; + } + + public ByteString(byte[] p0) {} + + public String base64() { + return null; + } + + public String base64Url() { + return null; + } + + public String hex() { + return null; + } + + public String string(Charset p0) { + return null; + } + + public String toString() { + return null; + } + + public String utf8() { + return null; + } + + public boolean equals(Object p0) { + return false; + } + + public boolean rangeEquals(int p0, ByteString p1, int p2, int p3) { + return false; + } + + public boolean rangeEquals(int p0, byte[] p1, int p2, int p3) { + return false; + } + + public byte internalGet$okio(int p0) { + return 0; + } + + public byte[] internalArray$okio() { + return null; + } + + public byte[] toByteArray() { + return null; + } + + public final ByteString substring() { + return null; + } + + public final ByteString substring(int p0) { + return null; + } + + public final String getUtf8$okio() { + return null; + } + + public final boolean endsWith(ByteString p0) { + return false; + } + + public final boolean endsWith(byte[] p0) { + return false; + } + + public final boolean startsWith(ByteString p0) { + return false; + } + + public final boolean startsWith(byte[] p0) { + return false; + } + + public final byte getByte(int p0) { + return 0; + } + + public final byte[] getData$okio() { + return null; + } + + public final int getHashCode$okio() { + return 0; + } + + public final int indexOf(ByteString p0) { + return 0; + } + + public final int indexOf(ByteString p0, int p1) { + return 0; + } + + public final int indexOf(byte[] p0) { + return 0; + } + + public final int lastIndexOf(ByteString p0) { + return 0; + } + + public final int lastIndexOf(ByteString p0, int p1) { + return 0; + } + + public final int lastIndexOf(byte[] p0) { + return 0; + } + + public final int size() { + return 0; + } + + public final void setHashCode$okio(int p0) {} + + public final void setUtf8$okio(String p0) {} + + public int compareTo(ByteString p0) { + return 0; + } + + public int getSize$okio() { + return 0; + } + + public int hashCode() { + return 0; + } + + public int indexOf(byte[] p0, int p1) { + return 0; + } + + public int lastIndexOf(byte[] p0, int p1) { + return 0; + } + + public static ByteString EMPTY = null; + + public static ByteString decodeBase64(String p0) { + return null; + } + + public static ByteString decodeHex(String p0) { + return null; + } + + public static ByteString encodeString(String p0, Charset p1) { + return null; + } + + public static ByteString encodeUtf8(String p0) { + return null; + } + + public static ByteString of(ByteBuffer p0) { + return null; + } + + public static ByteString of(byte... p0) { + return null; + } + + public static ByteString of(byte[] p0, int p1, int p2) { + return null; + } + + public static ByteString read(InputStream p0, int p1) { + return null; + } + + public static ByteString.Companion Companion = null; + + public void write$okio(Buffer p0, int p1, int p2) {} + + public void write(OutputStream p0) {} + + static public class Companion { + protected Companion() {} + + public final ByteString decodeBase64(String p0) { + return null; + } + + public final ByteString decodeHex(String p0) { + return null; + } + + public final ByteString encodeString(String p0, Charset p1) { + return null; + } + + public final ByteString encodeUtf8(String p0) { + return null; + } + + public final ByteString of(ByteBuffer p0) { + return null; + } + + public final ByteString of(byte... p0) { + return null; + } + + public final ByteString of(byte[] p0, int p1, int p2) { + return null; + } + + public final ByteString read(InputStream p0, int p1) { + return null; + } + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okio/Options.java b/java/ql/test/stubs/okhttp-4.9.3/okio/Options.java new file mode 100644 index 00000000000..13011a0c17a --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okio/Options.java @@ -0,0 +1,28 @@ +// Generated automatically from okio.Options for testing purposes + +package okio; + +import java.util.Collection; +import java.util.RandomAccess; +import kotlin.collections.AbstractList; +import okio.ByteString; + +public class Options extends AbstractList implements RandomAccess +{ + protected Options() {} + public ByteString get(int p0){ return null; } + public final ByteString[] getByteStrings$okio(){ return null; } + public final int[] getTrie$okio(){ return null; } + public int getSize(){ return 0; } + public static Options of(ByteString... p0){ return null; } + public static Options.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final Options of(ByteString... p0){ return null; } + } + public int size() { return 0; } + public boolean containsAll(Collection c) { return false; } + public boolean removeAll(Collection c) { return false; } + public boolean retainAll(Collection c) { return false; } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okio/Segment.java b/java/ql/test/stubs/okhttp-4.9.3/okio/Segment.java new file mode 100644 index 00000000000..4a31e4d31b3 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okio/Segment.java @@ -0,0 +1,31 @@ +// Generated automatically from okio.Segment for testing purposes + +package okio; + + +public class Segment +{ + public Segment next = null; + public Segment prev = null; + public Segment(){} + public Segment(byte[] p0, int p1, int p2, boolean p3, boolean p4){} + public boolean owner = false; + public boolean shared = false; + public final Segment pop(){ return null; } + public final Segment push(Segment p0){ return null; } + public final Segment sharedCopy(){ return null; } + public final Segment split(int p0){ return null; } + public final Segment unsharedCopy(){ return null; } + public final byte[] data = null; + public final void compact(){} + public final void writeTo(Segment p0, int p1){} + public int limit = 0; + public int pos = 0; + public static Segment.Companion Companion = null; + public static int SHARE_MINIMUM = 0; + public static int SIZE = 0; + static public class Companion + { + protected Companion() {} + } +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okio/Sink.java b/java/ql/test/stubs/okhttp-4.9.3/okio/Sink.java new file mode 100644 index 00000000000..0f6721212de --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okio/Sink.java @@ -0,0 +1,16 @@ +// Generated automatically from okio.Sink for testing purposes + +package okio; + +import java.io.Closeable; +import java.io.Flushable; +import okio.Buffer; +import okio.Timeout; + +public interface Sink extends Closeable, Flushable +{ + Timeout timeout(); + void close(); + void flush(); + void write(Buffer p0, long p1); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okio/Source.java b/java/ql/test/stubs/okhttp-4.9.3/okio/Source.java new file mode 100644 index 00000000000..561b3b876c0 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okio/Source.java @@ -0,0 +1,14 @@ +// Generated automatically from okio.Source for testing purposes + +package okio; + +import java.io.Closeable; +import okio.Buffer; +import okio.Timeout; + +public interface Source extends Closeable +{ + Timeout timeout(); + long read(Buffer p0, long p1); + void close(); +} diff --git a/java/ql/test/stubs/okhttp-4.9.3/okio/Timeout.java b/java/ql/test/stubs/okhttp-4.9.3/okio/Timeout.java new file mode 100644 index 00000000000..0d7953fa324 --- /dev/null +++ b/java/ql/test/stubs/okhttp-4.9.3/okio/Timeout.java @@ -0,0 +1,30 @@ +// Generated automatically from okio.Timeout for testing purposes + +package okio; + +import java.util.concurrent.TimeUnit; +import kotlin.Unit; +import kotlin.jvm.functions.Function0; + +public class Timeout +{ + public Timeout clearDeadline(){ return null; } + public Timeout clearTimeout(){ return null; } + public Timeout deadlineNanoTime(long p0){ return null; } + public Timeout timeout(long p0, TimeUnit p1){ return null; } + public Timeout(){} + public boolean hasDeadline(){ return false; } + public final Timeout deadline(long p0, TimeUnit p1){ return null; } + public final void intersectWith(Timeout p0, Function0 p1){} + public final void waitUntilNotified(Object p0){} + public long deadlineNanoTime(){ return 0; } + public long timeoutNanos(){ return 0; } + public static Timeout NONE = null; + public static Timeout.Companion Companion = null; + public void throwIfReached(){} + static public class Companion + { + protected Companion() {} + public final long minTimeout(long p0, long p1){ return 0; } + } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/Function.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/Function.java new file mode 100644 index 00000000000..ec16743fa7a --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/Function.java @@ -0,0 +1,8 @@ +// Generated automatically from kotlin.Function for testing purposes + +package kotlin; + + +public interface Function +{ +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/Pair.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/Pair.java new file mode 100644 index 00000000000..74869657cb4 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/Pair.java @@ -0,0 +1,19 @@ +// Generated automatically from kotlin.Pair for testing purposes + +package kotlin; + +import java.io.Serializable; + +public class Pair implements Serializable +{ + protected Pair() {} + public Pair(A p0, B p1){} + public String toString(){ return null; } + public boolean equals(Object p0){ return false; } + public final A component1(){ return null; } + public final A getFirst(){ return null; } + public final B component2(){ return null; } + public final B getSecond(){ return null; } + public final Pair copy(A p0, B p1){ return null; } + public int hashCode(){ return 0; } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/Unit.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/Unit.java new file mode 100644 index 00000000000..c2aeb7e3616 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/Unit.java @@ -0,0 +1,11 @@ +// Generated automatically from kotlin.Unit for testing purposes + +package kotlin; + + +public class Unit +{ + protected Unit() {} + public String toString(){ return null; } + public static Unit INSTANCE = null; +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/AbstractCollection.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/AbstractCollection.java new file mode 100644 index 00000000000..48555f6818e --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/AbstractCollection.java @@ -0,0 +1,26 @@ +// Generated automatically from kotlin.collections.AbstractCollection for testing purposes + +package kotlin.collections; + +import java.util.Collection; +import java.util.Iterator; +import kotlin.jvm.internal.markers.KMappedMarker; + +abstract public class AbstractCollection implements Collection, KMappedMarker +{ + protected AbstractCollection(){} + public T[] toArray(T[] p0){ return null; } + public Object[] toArray(){ return null; } + public String toString(){ return null; } + public abstract Iterator iterator(); + public abstract int getSize(); + public boolean add(E p0){ return false; } + public boolean addAll(Collection p0){ return false; } + public boolean contains(Object p0){ return false; } + public boolean containsAll(Collection p0){ return false; } + public boolean isEmpty(){ return false; } + public boolean remove(Object p0){ return false; } + public boolean removeAll(Collection p0){ return false; } + public boolean retainAll(Collection p0){ return false; } + public void clear(){} +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/AbstractList.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/AbstractList.java new file mode 100644 index 00000000000..1a11dbf9132 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/AbstractList.java @@ -0,0 +1,40 @@ +// Generated automatically from kotlin.collections.AbstractList for testing purposes + +package kotlin.collections; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import kotlin.collections.AbstractCollection; +import kotlin.jvm.internal.markers.KMappedMarker; + +abstract public class AbstractList extends AbstractCollection implements KMappedMarker, List +{ + protected AbstractList(){} + public E remove(int p0){ return null; } + public E set(int p0, E p1){ return null; } + public Iterator iterator(){ return null; } + public List subList(int p0, int p1){ return null; } + public ListIterator listIterator(){ return null; } + public ListIterator listIterator(int p0){ return null; } + public abstract E get(int p0); + public abstract int getSize(); + public boolean addAll(int p0, Collection p1){ return false; } + public boolean equals(Object p0){ return false; } + public int hashCode(){ return 0; } + public int indexOf(Object p0){ return 0; } + public int lastIndexOf(Object p0){ return 0; } + public static AbstractList.Companion Companion = null; + public void add(int p0, E p1){} + static public class Companion + { + protected Companion() {} + public final boolean orderedEquals$kotlin_stdlib(Collection p0, Collection p1){ return false; } + public final int orderedHashCode$kotlin_stdlib(Collection p0){ return 0; } + public final void checkBoundsIndexes$kotlin_stdlib(int p0, int p1, int p2){} + public final void checkElementIndex$kotlin_stdlib(int p0, int p1){} + public final void checkPositionIndex$kotlin_stdlib(int p0, int p1){} + public final void checkRangeIndexes$kotlin_stdlib(int p0, int p1, int p2){} + } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/IntIterator.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/IntIterator.java new file mode 100644 index 00000000000..87ed291f07d --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/collections/IntIterator.java @@ -0,0 +1,14 @@ +// Generated automatically from kotlin.collections.IntIterator for testing purposes + +package kotlin.collections; + +import java.util.Iterator; +import kotlin.jvm.internal.markers.KMappedMarker; + +abstract public class IntIterator implements Iterator, KMappedMarker +{ + public IntIterator(){} + public abstract int nextInt(); + public final Integer next(){ return null; } + public void remove(){} +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/functions/Function0.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/functions/Function0.java new file mode 100644 index 00000000000..93c5085ec5f --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/functions/Function0.java @@ -0,0 +1,10 @@ +// Generated automatically from kotlin.jvm.functions.Function0 for testing purposes + +package kotlin.jvm.functions; + +import kotlin.Function; + +public interface Function0 extends Function +{ + R invoke(); +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/functions/Function1.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/functions/Function1.java new file mode 100644 index 00000000000..775d4d8369b --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/functions/Function1.java @@ -0,0 +1,10 @@ +// Generated automatically from kotlin.jvm.functions.Function1 for testing purposes + +package kotlin.jvm.functions; + +import kotlin.Function; + +public interface Function1 extends Function +{ + R invoke(P1 p0); +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/internal/markers/KMappedMarker.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/internal/markers/KMappedMarker.java new file mode 100644 index 00000000000..08178fd7cc5 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/jvm/internal/markers/KMappedMarker.java @@ -0,0 +1,8 @@ +// Generated automatically from kotlin.jvm.internal.markers.KMappedMarker for testing purposes + +package kotlin.jvm.internal.markers; + + +public interface KMappedMarker +{ +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/ClosedRange.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/ClosedRange.java new file mode 100644 index 00000000000..36880bd56db --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/ClosedRange.java @@ -0,0 +1,12 @@ +// Generated automatically from kotlin.ranges.ClosedRange for testing purposes + +package kotlin.ranges; + + +public interface ClosedRange> +{ + T getEndInclusive(); + T getStart(); + boolean contains(T p0); + boolean isEmpty(); +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/IntProgression.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/IntProgression.java new file mode 100644 index 00000000000..3cf69027397 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/IntProgression.java @@ -0,0 +1,26 @@ +// Generated automatically from kotlin.ranges.IntProgression for testing purposes + +package kotlin.ranges; + +import kotlin.collections.IntIterator; +import kotlin.jvm.internal.markers.KMappedMarker; + +public class IntProgression implements Iterable, KMappedMarker +{ + protected IntProgression() {} + public IntIterator iterator(){ return null; } + public IntProgression(int p0, int p1, int p2){} + public String toString(){ return null; } + public boolean equals(Object p0){ return false; } + public boolean isEmpty(){ return false; } + public final int getFirst(){ return 0; } + public final int getLast(){ return 0; } + public final int getStep(){ return 0; } + public int hashCode(){ return 0; } + public static IntProgression.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final IntProgression fromClosedRange(int p0, int p1, int p2){ return null; } + } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/IntRange.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/IntRange.java new file mode 100644 index 00000000000..663437f37c7 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/ranges/IntRange.java @@ -0,0 +1,26 @@ +// Generated automatically from kotlin.ranges.IntRange for testing purposes + +package kotlin.ranges; + +import kotlin.ranges.ClosedRange; +import kotlin.ranges.IntProgression; + +public class IntRange extends IntProgression implements ClosedRange +{ + protected IntRange() {} + public IntRange(int p0, int p1){} + public Integer getEndInclusive(){ return null; } + public Integer getStart(){ return null; } + public String toString(){ return null; } + public boolean contains(int p0){ return false; } + public boolean equals(Object p0){ return false; } + public boolean isEmpty(){ return false; } + public int hashCode(){ return 0; } + public static IntRange.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final IntRange getEMPTY(){ return null; } + } + public boolean contains(Integer p0) { return false; } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/sequences/Sequence.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/sequences/Sequence.java new file mode 100644 index 00000000000..6f57a5a443a --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/sequences/Sequence.java @@ -0,0 +1,10 @@ +// Generated automatically from kotlin.sequences.Sequence for testing purposes + +package kotlin.sequences; + +import java.util.Iterator; + +public interface Sequence +{ + Iterator iterator(); +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/FlagEnum.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/FlagEnum.java new file mode 100644 index 00000000000..8ec20898544 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/FlagEnum.java @@ -0,0 +1,10 @@ +// Generated automatically from kotlin.text.FlagEnum for testing purposes + +package kotlin.text; + + +interface FlagEnum +{ + int getMask(); + int getValue(); +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchGroup.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchGroup.java new file mode 100644 index 00000000000..e90a0ea9264 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchGroup.java @@ -0,0 +1,19 @@ +// Generated automatically from kotlin.text.MatchGroup for testing purposes + +package kotlin.text; + +import kotlin.ranges.IntRange; + +public class MatchGroup +{ + protected MatchGroup() {} + public MatchGroup(String p0, IntRange p1){} + public String toString(){ return null; } + public boolean equals(Object p0){ return false; } + public final IntRange component2(){ return null; } + public final IntRange getRange(){ return null; } + public final MatchGroup copy(String p0, IntRange p1){ return null; } + public final String component1(){ return null; } + public final String getValue(){ return null; } + public int hashCode(){ return 0; } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchGroupCollection.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchGroupCollection.java new file mode 100644 index 00000000000..ca401ed1a98 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchGroupCollection.java @@ -0,0 +1,12 @@ +// Generated automatically from kotlin.text.MatchGroupCollection for testing purposes + +package kotlin.text; + +import java.util.Collection; +import kotlin.jvm.internal.markers.KMappedMarker; +import kotlin.text.MatchGroup; + +public interface MatchGroupCollection extends Collection, KMappedMarker +{ + MatchGroup get(int p0); +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchResult.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchResult.java new file mode 100644 index 00000000000..888b629712c --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/MatchResult.java @@ -0,0 +1,24 @@ +// Generated automatically from kotlin.text.MatchResult for testing purposes + +package kotlin.text; + +import java.util.List; +import kotlin.ranges.IntRange; +import kotlin.text.MatchGroupCollection; + +public interface MatchResult +{ + IntRange getRange(); + List getGroupValues(); + MatchGroupCollection getGroups(); + MatchResult next(); + MatchResult.Destructured getDestructured(); + String getValue(); + static public class Destructured + { + protected Destructured() {} + public Destructured(MatchResult p0){} + public final List toList(){ return null; } + public final MatchResult getMatch(){ return null; } + } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/Regex.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/Regex.java new file mode 100644 index 00000000000..f587f461b2e --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/Regex.java @@ -0,0 +1,42 @@ +// Generated automatically from kotlin.text.Regex for testing purposes + +package kotlin.text; + +import java.io.Serializable; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; +import kotlin.jvm.functions.Function1; +import kotlin.sequences.Sequence; +import kotlin.text.MatchResult; +import kotlin.text.RegexOption; + +public class Regex implements Serializable +{ + protected Regex() {} + public Regex(Pattern p0){} + public Regex(String p0){} + public Regex(String p0, RegexOption p1){} + public Regex(String p0, Set p1){} + public String toString(){ return null; } + public final List split(CharSequence p0, int p1){ return null; } + public final MatchResult find(CharSequence p0, int p1){ return null; } + public final MatchResult matchEntire(CharSequence p0){ return null; } + public final Pattern toPattern(){ return null; } + public final Sequence findAll(CharSequence p0, int p1){ return null; } + public final Set getOptions(){ return null; } + public final String getPattern(){ return null; } + public final String replace(CharSequence p0, Function1 p1){ return null; } + public final String replace(CharSequence p0, String p1){ return null; } + public final String replaceFirst(CharSequence p0, String p1){ return null; } + public final boolean containsMatchIn(CharSequence p0){ return false; } + public final boolean matches(CharSequence p0){ return false; } + public static Regex.Companion Companion = null; + static public class Companion + { + protected Companion() {} + public final Regex fromLiteral(String p0){ return null; } + public final String escape(String p0){ return null; } + public final String escapeReplacement(String p0){ return null; } + } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/RegexOption.java b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/RegexOption.java new file mode 100644 index 00000000000..7cc222eb40a --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/kotlin/text/RegexOption.java @@ -0,0 +1,12 @@ +// Generated automatically from kotlin.text.RegexOption for testing purposes + +package kotlin.text; + + +public enum RegexOption +{ + CANON_EQ, COMMENTS, DOT_MATCHES_ALL, IGNORE_CASE, LITERAL, MULTILINE, UNIX_LINES; + private RegexOption() {} + public int getMask(){ return 0; } + public int getValue(){ return 0; } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Call.java b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Call.java new file mode 100644 index 00000000000..a341e37ae74 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Call.java @@ -0,0 +1,20 @@ +// Generated automatically from retrofit2.Call for testing purposes + +package retrofit2; + +import okhttp3.Request; +import okio.Timeout; +import retrofit2.Callback; +import retrofit2.Response; + +public interface Call extends Cloneable +{ + Call clone(); + Request request(); + Response execute(); + Timeout timeout(); + boolean isCanceled(); + boolean isExecuted(); + void cancel(); + void enqueue(Callback p0); +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/retrofit2/CallAdapter.java b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/CallAdapter.java new file mode 100644 index 00000000000..7c79f2ce004 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/CallAdapter.java @@ -0,0 +1,22 @@ +// Generated automatically from retrofit2.CallAdapter for testing purposes + +package retrofit2; + +import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import retrofit2.Call; +import retrofit2.Retrofit; + +public interface CallAdapter +{ + T adapt(Call p0); + Type responseType(); + abstract static public class Factory + { + protected static Class getRawType(Type p0){ return null; } + protected static Type getParameterUpperBound(int p0, ParameterizedType p1){ return null; } + public Factory(){} + public abstract CallAdapter get(Type p0, Annotation[] p1, Retrofit p2); + } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Callback.java b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Callback.java new file mode 100644 index 00000000000..885dc933a0b --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Callback.java @@ -0,0 +1,12 @@ +// Generated automatically from retrofit2.Callback for testing purposes + +package retrofit2; + +import retrofit2.Call; +import retrofit2.Response; + +public interface Callback +{ + void onFailure(Call p0, Throwable p1); + void onResponse(Call p0, Response p1); +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Converter.java b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Converter.java new file mode 100644 index 00000000000..bc85c5c1015 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Converter.java @@ -0,0 +1,24 @@ +// Generated automatically from retrofit2.Converter for testing purposes + +package retrofit2; + +import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import okhttp3.RequestBody; +import okhttp3.ResponseBody; +import retrofit2.Retrofit; + +public interface Converter +{ + T convert(F p0); + abstract static public class Factory + { + protected static Class getRawType(Type p0){ return null; } + protected static Type getParameterUpperBound(int p0, ParameterizedType p1){ return null; } + public Converter requestBodyConverter(Type p0, Annotation[] p1, Annotation[] p2, Retrofit p3){ return null; } + public Converter stringConverter(Type p0, Annotation[] p1, Retrofit p2){ return null; } + public Converter responseBodyConverter(Type p0, Annotation[] p1, Retrofit p2){ return null; } + public Factory(){} + } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Response.java b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Response.java new file mode 100644 index 00000000000..542ce3a3ba8 --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Response.java @@ -0,0 +1,25 @@ +// Generated automatically from retrofit2.Response for testing purposes + +package retrofit2; + +import okhttp3.Headers; +import okhttp3.ResponseBody; + +public class Response +{ + protected Response() {} + public Headers headers(){ return null; } + public Response raw(){ return null; } + public ResponseBody errorBody(){ return null; } + public String message(){ return null; } + public String toString(){ return null; } + public T body(){ return null; } + public boolean isSuccessful(){ return false; } + public int code(){ return 0; } + public static Response error(ResponseBody p0, Response p1){ return null; } + public static Response error(int p0, ResponseBody p1){ return null; } + public static Response success(T p0){ return null; } + public static Response success(T p0, Headers p1){ return null; } + public static Response success(T p0, Response p1){ return null; } + public static Response success(int p0, T p1){ return null; } +} diff --git a/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Retrofit.java b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Retrofit.java new file mode 100644 index 00000000000..9d87826085c --- /dev/null +++ b/java/ql/test/stubs/retrofit-2.9.0/retrofit2/Retrofit.java @@ -0,0 +1,51 @@ +// Generated automatically from retrofit2.Retrofit for testing purposes + +package retrofit2; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.net.URL; +import java.util.List; +import java.util.concurrent.Executor; +import okhttp3.Call; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.RequestBody; +import okhttp3.ResponseBody; +import retrofit2.CallAdapter; +import retrofit2.Converter; + +public class Retrofit +{ + protected Retrofit() {} + public Converter nextResponseBodyConverter(Converter.Factory p0, Type p1, Annotation[] p2){ return null; } + public Converter responseBodyConverter(Type p0, Annotation[] p1){ return null; } + public Converter nextRequestBodyConverter(Converter.Factory p0, Type p1, Annotation[] p2, Annotation[] p3){ return null; } + public Converter requestBodyConverter(Type p0, Annotation[] p1, Annotation[] p2){ return null; } + public Converter stringConverter(Type p0, Annotation[] p1){ return null; } + public T create(Class p0){ return null; } + public Call.Factory callFactory(){ return null; } + public CallAdapter callAdapter(Type p0, Annotation[] p1){ return null; } + public CallAdapter nextCallAdapter(CallAdapter.Factory p0, Type p1, Annotation[] p2){ return null; } + public Executor callbackExecutor(){ return null; } + public HttpUrl baseUrl(){ return null; } + public List callAdapterFactories(){ return null; } + public List converterFactories(){ return null; } + public Retrofit.Builder newBuilder(){ return null; } + static public class Builder + { + public Builder(){} + public List callAdapterFactories(){ return null; } + public List converterFactories(){ return null; } + public Retrofit build(){ return null; } + public Retrofit.Builder addCallAdapterFactory(CallAdapter.Factory p0){ return null; } + public Retrofit.Builder addConverterFactory(Converter.Factory p0){ return null; } + public Retrofit.Builder baseUrl(HttpUrl p0){ return null; } + public Retrofit.Builder baseUrl(String p0){ return null; } + public Retrofit.Builder baseUrl(URL p0){ return null; } + public Retrofit.Builder callFactory(Call.Factory p0){ return null; } + public Retrofit.Builder callbackExecutor(Executor p0){ return null; } + public Retrofit.Builder client(OkHttpClient p0){ return null; } + public Retrofit.Builder validateEagerly(boolean p0){ return null; } + } +} From 1cf4b6076915178c1ae32b59b9cdf100815875b6 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 2 May 2022 15:43:07 +0200 Subject: [PATCH 109/171] Simplify non-https-url query --- java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql b/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql index da5d847b4dd..123313e2177 100644 --- a/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql +++ b/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql @@ -14,10 +14,7 @@ import java import semmle.code.java.security.HttpsUrlsQuery import DataFlow::PathGraph -from DataFlow::PathNode source, DataFlow::PathNode sink, MethodAccess m, HttpStringLiteral s -where - source.getNode().asExpr() = s and - sink.getNode().asExpr() = m.getQualifier() and - any(HttpStringToUrlOpenMethodFlowConfig c).hasFlowPath(source, sink) -select m, source, sink, "URL may have been constructed with HTTP protocol, using $@.", s, - "this source" +from DataFlow::PathNode source, DataFlow::PathNode sink +where any(HttpStringToUrlOpenMethodFlowConfig c).hasFlowPath(source, sink) +select sink.getNode(), source, sink, "URL may have been constructed with HTTP protocol, using $@.", + source.getNode(), "this source" From 9a35aba465aee7fe52b9213278af97810ea27095 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 2 May 2022 15:45:44 +0200 Subject: [PATCH 110/171] Add change notes --- .../ql/lib/change-notes/2022-05-02-okhttp-retrofit-models.md | 4 ++++ .../src/change-notes/2022-05-02-non-https-urls-simplified.md | 5 +++++ 2 files changed, 9 insertions(+) create mode 100644 java/ql/lib/change-notes/2022-05-02-okhttp-retrofit-models.md create mode 100644 java/ql/src/change-notes/2022-05-02-non-https-urls-simplified.md diff --git a/java/ql/lib/change-notes/2022-05-02-okhttp-retrofit-models.md b/java/ql/lib/change-notes/2022-05-02-okhttp-retrofit-models.md new file mode 100644 index 00000000000..f575b10cfec --- /dev/null +++ b/java/ql/lib/change-notes/2022-05-02-okhttp-retrofit-models.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added models for the libraries OkHttp and Retrofit. \ No newline at end of file diff --git a/java/ql/src/change-notes/2022-05-02-non-https-urls-simplified.md b/java/ql/src/change-notes/2022-05-02-non-https-urls-simplified.md new file mode 100644 index 00000000000..9baa9a9bbae --- /dev/null +++ b/java/ql/src/change-notes/2022-05-02-non-https-urls-simplified.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* The query `java/non-https-urls` has been simplified +and no longer requires its sinks to be `MethodAccess`es. \ No newline at end of file From 29b430e49b7e56f58571a8ad6451148d94117892 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 2 May 2022 16:55:01 +0200 Subject: [PATCH 111/171] Make commits private --- java/ql/lib/semmle/code/java/frameworks/OkHttp.qll | 2 +- java/ql/lib/semmle/code/java/frameworks/Retrofit.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll b/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll index 36e23d45881..12b09065183 100644 --- a/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll +++ b/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll @@ -3,7 +3,7 @@ */ import java -import semmle.code.java.dataflow.ExternalFlow +private import semmle.code.java.dataflow.ExternalFlow private class OkHttpOpenUrlSinks extends SinkModelCsv { override predicate row(string row) { diff --git a/java/ql/lib/semmle/code/java/frameworks/Retrofit.qll b/java/ql/lib/semmle/code/java/frameworks/Retrofit.qll index cb1aaa87667..bbbd659ee85 100644 --- a/java/ql/lib/semmle/code/java/frameworks/Retrofit.qll +++ b/java/ql/lib/semmle/code/java/frameworks/Retrofit.qll @@ -3,7 +3,7 @@ */ import java -import semmle.code.java.dataflow.ExternalFlow +private import semmle.code.java.dataflow.ExternalFlow private class RetrofitOpenUrlSinks extends SinkModelCsv { override predicate row(string row) { From de8b5f927b5eeb5ebd40bb38858a932794cd42e6 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 2 May 2022 16:55:11 +0200 Subject: [PATCH 112/171] Adjust test expectations --- .../security/CWE-311/CWE-319/HttpsUrls.expected | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.expected b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.expected index af4bc51c793..a6a8886c4b3 100644 --- a/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.expected +++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.expected @@ -19,7 +19,7 @@ nodes | HttpsUrlsTest.java:92:50:92:50 | u | semmle.label | u | subpaths #select -| HttpsUrlsTest.java:28:50:28:67 | openConnection(...) | HttpsUrlsTest.java:23:23:23:31 | "http://" : String | HttpsUrlsTest.java:28:50:28:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:23:23:23:31 | "http://" | this source | -| HttpsUrlsTest.java:41:50:41:67 | openConnection(...) | HttpsUrlsTest.java:36:23:36:28 | "http" : String | HttpsUrlsTest.java:41:50:41:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:36:23:36:28 | "http" | this source | -| HttpsUrlsTest.java:55:50:55:67 | openConnection(...) | HttpsUrlsTest.java:49:23:49:31 | "http://" : String | HttpsUrlsTest.java:55:50:55:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:49:23:49:31 | "http://" | this source | -| HttpsUrlsTest.java:92:50:92:67 | openConnection(...) | HttpsUrlsTest.java:87:23:87:28 | "http" : String | HttpsUrlsTest.java:92:50:92:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:87:23:87:28 | "http" | this source | +| HttpsUrlsTest.java:28:50:28:50 | u | HttpsUrlsTest.java:23:23:23:31 | "http://" : String | HttpsUrlsTest.java:28:50:28:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:23:23:23:31 | "http://" | this source | +| HttpsUrlsTest.java:41:50:41:50 | u | HttpsUrlsTest.java:36:23:36:28 | "http" : String | HttpsUrlsTest.java:41:50:41:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:36:23:36:28 | "http" | this source | +| HttpsUrlsTest.java:55:50:55:50 | u | HttpsUrlsTest.java:49:23:49:31 | "http://" : String | HttpsUrlsTest.java:55:50:55:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:49:23:49:31 | "http://" | this source | +| HttpsUrlsTest.java:92:50:92:50 | u | HttpsUrlsTest.java:87:23:87:28 | "http" : String | HttpsUrlsTest.java:92:50:92:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:87:23:87:28 | "http" | this source | From 19e4d34581533e1c78fb248a99d19005f12315d2 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Tue, 3 May 2022 10:08:29 +0200 Subject: [PATCH 113/171] Update ruby/ql/lib/change-notes/2022-04-30-update-grammar.md Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- ruby/ql/lib/change-notes/2022-04-30-update-grammar.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/change-notes/2022-04-30-update-grammar.md b/ruby/ql/lib/change-notes/2022-04-30-update-grammar.md index 34a485c94e6..a5190ee7368 100644 --- a/ruby/ql/lib/change-notes/2022-04-30-update-grammar.md +++ b/ruby/ql/lib/change-notes/2022-04-30-update-grammar.md @@ -1,4 +1,4 @@ --- category: fix --- -The TreeSitter Ruby grammar has been updated; this fixes several issues where Ruby code was parsed incorrectly. +The Tree-sitter Ruby grammar has been updated; this fixes several issues where Ruby code was parsed incorrectly. From 89c4b6c235a04aba06afadea359d70907fd93252 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 3 May 2022 14:06:15 +0200 Subject: [PATCH 114/171] Ruby: Fix `isLocalSourceNode` implementation The old code was equivalent with the code below, which seems wrong ``` not n instanceof ExprNode or n instanceof ExprNode and localFlowStepTypeTracker+(..., n) ``` From running on real DB I found that this meant that the following node types were also included as local source nodes: - `TReturningNode` - `TSynthReturnNode` - `TSummaryNode` - `TSsaDefinitionNode` My understanding is that the first 3 should not be included. I would guess that SsaDefinitionNode should indeed be included as a LocalSourceNode, but I'm not 100% sure, so I'll see what the test results say before making further changes. --- ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index d5b2f44c82f..6eeec53f141 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -303,11 +303,12 @@ private module Cached { n instanceof PostUpdateNodes::ExprPostUpdateNode or // Expressions that can't be reached from another entry definition or expression. + n instanceof ExprNode and not localFlowStepTypeTracker+(any(Node n0 | n0 instanceof ExprNode or entrySsaDefinition(n0) - ), n.(ExprNode)) + ), n) or // Ensure all entry SSA definitions are local sources -- for parameters, this // is needed by type tracking. Note that when the parameter has a default value, From fbceb8de5798b0918dde367377754a8d7526886b Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 3 May 2022 14:40:40 +0200 Subject: [PATCH 115/171] Update java/ql/lib/semmle/code/java/frameworks/OkHttp.qll Co-authored-by: Chris Smowton --- java/ql/lib/semmle/code/java/frameworks/OkHttp.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll b/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll index 12b09065183..cc4557bcd03 100644 --- a/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll +++ b/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll @@ -35,7 +35,6 @@ private class OKHttpSummaries extends SummaryModelCsv { "okhttp3;HttpUrl$Builder;false;encodedQuery;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;encodedUsername;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;fragment;;;Argument[-1];ReturnValue;value", - "okhttp3;HttpUrl$Builder;false;fragment;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;host;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;password;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;port;;;Argument[-1];ReturnValue;value", From 6cacf7b9a62476df69eea519b25a67c4eba74d66 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 3 May 2022 14:43:31 +0200 Subject: [PATCH 116/171] Ruby: `isLocalSourceNode` needs `SynthReturnNode` --- .../ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index 6eeec53f141..8072083ff65 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -302,6 +302,11 @@ private module Cached { or n instanceof PostUpdateNodes::ExprPostUpdateNode or + // TODO: Explain why SynthReturnNode is needed! + // if we don't include this, we are not able to find this call: + // https://github.com/github/codeql/blob/976daddd36a63bf46836d141d04172e90bb4b33c/ruby/ql/test/library-tests/frameworks/http_clients/NetHttp.rb#L24 + n instanceof SynthReturnNode + or // Expressions that can't be reached from another entry definition or expression. n instanceof ExprNode and not localFlowStepTypeTracker+(any(Node n0 | From a7b43f73569ce0eeb9b4581b1f72052762e9e8ad Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 3 May 2022 14:45:33 +0200 Subject: [PATCH 117/171] Ruby: Accept changes to TypeTracker tests Since this is not using inline-expectation-tests, I'm not entirely sure whether these changes are OK or not, so hope to get someone else to signoff on that. --- .../dataflow/type-tracker/TypeTracker.expected | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected index 3c77ddc8b02..efbf76dfc76 100644 --- a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected +++ b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected @@ -43,10 +43,6 @@ track | type_tracker.rb:12:1:16:3 | self in m | type tracker with call steps | type_tracker.rb:12:1:16:3 | self (m) | | type_tracker.rb:12:1:16:3 | self in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | self in m | | type_tracker.rb:13:5:13:7 | var | type tracker without call steps | type_tracker.rb:13:5:13:7 | var | -| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) | -| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:2:5:5:7 | self in field= | -| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field | -| type_tracker.rb:13:5:13:23 | ... = ... | type tracker without call steps | type_tracker.rb:13:5:13:23 | ... = ... | | type_tracker.rb:13:11:13:19 | Container | type tracker without call steps | type_tracker.rb:13:11:13:19 | Container | | type_tracker.rb:13:11:13:19 | [post] Container | type tracker without call steps | type_tracker.rb:13:11:13:19 | [post] Container | | type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) | @@ -63,7 +59,6 @@ track | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:14:17:14:23 | "hello" | | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps with content field | type_tracker.rb:14:5:14:7 | [post] var | -| type_tracker.rb:14:17:14:23 | ... = ... | type tracker without call steps | type_tracker.rb:14:17:14:23 | ... = ... | | type_tracker.rb:14:17:14:23 | [post] ... = ... | type tracker without call steps | type_tracker.rb:14:17:14:23 | [post] ... = ... | | type_tracker.rb:14:17:14:23 | __synth__0 | type tracker without call steps | type_tracker.rb:14:17:14:23 | __synth__0 | | type_tracker.rb:15:5:15:18 | [post] self | type tracker without call steps | type_tracker.rb:15:5:15:18 | [post] self | @@ -245,14 +240,6 @@ trackEnd | type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self in m | | type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:15:5:15:18 | self | | type_tracker.rb:13:5:13:7 | var | type_tracker.rb:13:5:13:7 | var | -| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:2:5:5:7 | self (field=) | -| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:2:5:5:7 | self in field= | -| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:3:9:3:23 | self | -| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:3:14:3:17 | self | -| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:7:5:9:7 | self in field | -| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:13:5:13:23 | ... = ... | -| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:14:5:14:7 | var | -| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:15:10:15:12 | var | | type_tracker.rb:13:11:13:19 | Container | type_tracker.rb:13:11:13:19 | Container | | type_tracker.rb:13:11:13:19 | [post] Container | type_tracker.rb:13:11:13:19 | [post] Container | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:2:5:5:7 | self (field=) | @@ -280,9 +267,6 @@ trackEnd | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:17:14:23 | ... = ... | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:17:14:23 | ... = ... | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:15:10:15:18 | call to field | -| type_tracker.rb:14:17:14:23 | ... = ... | type_tracker.rb:14:5:14:13 | __synth__0 | -| type_tracker.rb:14:17:14:23 | ... = ... | type_tracker.rb:14:5:14:23 | ... | -| type_tracker.rb:14:17:14:23 | ... = ... | type_tracker.rb:14:17:14:23 | ... = ... | | type_tracker.rb:14:17:14:23 | [post] ... = ... | type_tracker.rb:14:17:14:23 | [post] ... = ... | | type_tracker.rb:14:17:14:23 | __synth__0 | type_tracker.rb:14:17:14:23 | __synth__0 | | type_tracker.rb:15:5:15:18 | [post] self | type_tracker.rb:15:5:15:18 | [post] self | From 7b3a803d19eac50694def9acd919f252a35fad88 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 26 Apr 2022 11:16:51 +0200 Subject: [PATCH 118/171] Add flow step from startActivity to getIntent --- .../code/java/frameworks/android/Intent.qll | 19 ++++++++++++++ .../android/intent/AndroidManifest.xml | 22 ++++++++++++++++ .../intent/TestStartActivityToGetIntent.java | 25 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 java/ql/test/library-tests/frameworks/android/intent/AndroidManifest.xml create mode 100644 java/ql/test/library-tests/frameworks/android/intent/TestStartActivityToGetIntent.java diff --git a/java/ql/lib/semmle/code/java/frameworks/android/Intent.qll b/java/ql/lib/semmle/code/java/frameworks/android/Intent.qll index a92d2665213..7aaa6519075 100644 --- a/java/ql/lib/semmle/code/java/frameworks/android/Intent.qll +++ b/java/ql/lib/semmle/code/java/frameworks/android/Intent.qll @@ -176,6 +176,25 @@ class GrantWriteUriPermissionFlag extends GrantUriPermissionFlag { GrantWriteUriPermissionFlag() { this.hasName("FLAG_GRANT_WRITE_URI_PERMISSION") } } +/** + * A value-preserving step from the Intent argument of a `startActivity` call to + * a `getIntent` call in the Activity the Intent pointed to in its constructor. + */ +private class StartActivityIntentStep extends AdditionalValueStep { + override predicate step(DataFlow::Node n1, DataFlow::Node n2) { + exists(MethodAccess startActivity, MethodAccess getIntent, ClassInstanceExpr newIntent | + startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) and + getIntent.getMethod().overrides*(any(AndroidGetIntentMethod m)) and + newIntent.getConstructedType() instanceof TypeIntent and + DataFlow::localExprFlow(newIntent, startActivity.getArgument(0)) and + newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() = + getIntent.getReceiverType() and + n1.asExpr() = startActivity.getArgument(0) and + n2.asExpr() = getIntent + ) + } +} + private class IntentBundleFlowSteps extends SummaryModelCsv { override predicate row(string row) { row = diff --git a/java/ql/test/library-tests/frameworks/android/intent/AndroidManifest.xml b/java/ql/test/library-tests/frameworks/android/intent/AndroidManifest.xml new file mode 100644 index 00000000000..0be6a0ae8f8 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/android/intent/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/java/ql/test/library-tests/frameworks/android/intent/TestStartActivityToGetIntent.java b/java/ql/test/library-tests/frameworks/android/intent/TestStartActivityToGetIntent.java new file mode 100644 index 00000000000..3d497aac93d --- /dev/null +++ b/java/ql/test/library-tests/frameworks/android/intent/TestStartActivityToGetIntent.java @@ -0,0 +1,25 @@ +import android.app.Activity; +import android.content.Context; +import android.content.Intent; + +public class TestStartActivityToGetIntent { + + static Object source() { + return null; + } + + static void sink(Object sink) {} + + public void test(Context ctx) { + Intent intent = new Intent(null, SomeActivity.class); + intent.putExtra("data", (String) source()); + ctx.startActivity(intent); + } + + static class SomeActivity extends Activity { + + public void test() { + sink(getIntent().getStringExtra("data")); // $ hasValueFlow + } + } +} From cf55f180c4ac94b41c9dd71beb78cf35d0c580e3 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 26 Apr 2022 11:26:58 +0200 Subject: [PATCH 119/171] Add change note --- .../ql/lib/change-notes/2022-04-26-startactivity-flow-step.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 java/ql/lib/change-notes/2022-04-26-startactivity-flow-step.md diff --git a/java/ql/lib/change-notes/2022-04-26-startactivity-flow-step.md b/java/ql/lib/change-notes/2022-04-26-startactivity-flow-step.md new file mode 100644 index 00000000000..82d58183edd --- /dev/null +++ b/java/ql/lib/change-notes/2022-04-26-startactivity-flow-step.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +Added a data flow step for tainted Android intents that are sent to other activities and accessed there via `getIntent()`. \ No newline at end of file From 2d3b15f936f4c3fa28badc72f8164bfc5aa818ab Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Wed, 4 May 2022 12:32:59 +0200 Subject: [PATCH 120/171] Add more taint models --- .../semmle/code/java/frameworks/OkHttp.qll | 17 +++ .../library-tests/frameworks/okhttp/Test.java | 126 ++++++++++++++++++ 2 files changed, 143 insertions(+) diff --git a/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll b/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll index cc4557bcd03..da38b7af7e8 100644 --- a/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll +++ b/java/ql/lib/semmle/code/java/frameworks/OkHttp.qll @@ -23,31 +23,48 @@ private class OKHttpSummaries extends SummaryModelCsv { "okhttp3;HttpUrl;false;uri;;;Argument[-1];ReturnValue;taint", "okhttp3;HttpUrl;false;url;;;Argument[-1];ReturnValue;taint", "okhttp3;HttpUrl$Builder;false;addEncodedPathSegment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;addEncodedPathSegment;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;addEncodedPathSegments;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;addEncodedPathSegments;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;addEncodedQueryParameter;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;addEncodedQueryParameter;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;addPathSegment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;addPathSegment;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;addPathSegments;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;addPathSegments;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;addQueryParameter;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;addQueryParameter;;;Argument[0..1];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;build;;;Argument[-1];ReturnValue;taint", "okhttp3;HttpUrl$Builder;false;encodedFragment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;encodedFragment;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;encodedPassword;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;encodedPath;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;encodedPath;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;encodedQuery;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;encodedQuery;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;encodedUsername;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;fragment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;fragment;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;host;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;host;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;password;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;port;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;port;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;query;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;query;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;removeAllEncodedQueryParameters;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;removeAllQueryParameters;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;removePathSegment;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;scheme;;;Argument[-1];ReturnValue;value", "okhttp3;HttpUrl$Builder;false;scheme;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;setEncodedPathSegment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;setEncodedPathSegment;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;setEncodedQueryParameter;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;setEncodedQueryParameter;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;setPathSegment;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;setPathSegment;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;setQueryParameter;;;Argument[-1];ReturnValue;value", + "okhttp3;HttpUrl$Builder;false;setQueryParameter;;;Argument[0];Argument[-1];taint", "okhttp3;HttpUrl$Builder;false;username;;;Argument[-1];ReturnValue;value", ] } diff --git a/java/ql/test/library-tests/frameworks/okhttp/Test.java b/java/ql/test/library-tests/frameworks/okhttp/Test.java index 02950ccaa30..7d6517bddf0 100644 --- a/java/ql/test/library-tests/frameworks/okhttp/Test.java +++ b/java/ql/test/library-tests/frameworks/okhttp/Test.java @@ -28,6 +28,13 @@ public class Test { out = in.addEncodedPathSegment(null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;addEncodedPathSegment;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.addEncodedPathSegment(in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;addEncodedPathSegments;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -35,6 +42,13 @@ public class Test { out = in.addEncodedPathSegments(null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;addEncodedPathSegments;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.addEncodedPathSegments(in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;addEncodedQueryParameter;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -42,6 +56,13 @@ public class Test { out = in.addEncodedQueryParameter(null, null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;addEncodedQueryParameter;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.addEncodedQueryParameter(in, null); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;addPathSegment;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -49,6 +70,13 @@ public class Test { out = in.addPathSegment(null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;addPathSegment;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.addPathSegment(in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;addPathSegments;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -56,6 +84,13 @@ public class Test { out = in.addPathSegments(null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;addPathSegments;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.addPathSegments(in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;addQueryParameter;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -63,6 +98,20 @@ public class Test { out = in.addQueryParameter(null, null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;addQueryParameter;;;Argument[0..1];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.addQueryParameter(in, null); + sink(out); // $ hasTaintFlow + } + { + // "okhttp3;HttpUrl$Builder;false;addQueryParameter;;;Argument[0..1];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.addQueryParameter(null, in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;build;;;Argument[-1];ReturnValue;taint" HttpUrl out = null; @@ -77,6 +126,13 @@ public class Test { out = in.encodedFragment(null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;encodedFragment;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.encodedFragment(in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;encodedPassword;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -91,6 +147,13 @@ public class Test { out = in.encodedPath(null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;encodedPath;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.encodedPath(in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;encodedQuery;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -98,6 +161,13 @@ public class Test { out = in.encodedQuery(null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;encodedQuery;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.encodedQuery(in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;encodedUsername;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -112,6 +182,13 @@ public class Test { out = in.fragment(null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;fragment;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.fragment(in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;host;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -119,6 +196,13 @@ public class Test { out = in.host(null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;host;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.host(in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;password;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -133,6 +217,13 @@ public class Test { out = in.port(0); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;port;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + int in = (int) source(); + out.port(in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;query;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -140,6 +231,13 @@ public class Test { out = in.query(null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;query;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.query(in); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;removeAllEncodedQueryParameters;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -182,6 +280,13 @@ public class Test { out = in.setEncodedPathSegment(0, null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;setEncodedPathSegment;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + int in = (int) source(); + out.setEncodedPathSegment(in, null); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;setEncodedQueryParameter;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -189,6 +294,13 @@ public class Test { out = in.setEncodedQueryParameter(null, null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;setEncodedQueryParameter;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.setEncodedQueryParameter(in, null); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;setPathSegment;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -196,6 +308,13 @@ public class Test { out = in.setPathSegment(0, null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;setPathSegment;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + int in = (int) source(); + out.setPathSegment(in, null); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;setQueryParameter;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; @@ -203,6 +322,13 @@ public class Test { out = in.setQueryParameter(null, null); sink(out); // $ hasValueFlow } + { + // "okhttp3;HttpUrl$Builder;false;setQueryParameter;;;Argument[0];Argument[-1];taint" + HttpUrl.Builder out = null; + String in = (String) source(); + out.setQueryParameter(in, null); + sink(out); // $ hasTaintFlow + } { // "okhttp3;HttpUrl$Builder;false;username;;;Argument[-1];ReturnValue;value" HttpUrl.Builder out = null; From 7bd7bedb1be7df5004089570df226832992edc7a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 4 May 2022 16:12:20 +0200 Subject: [PATCH 121/171] Ruby: Simplify `isLocalSourceNode` implementation The need for `SynthReturnNode` goes away if we don't restrict the nodes that can't be reached from another entry definition or expression to be `ExprNode`s --- .../lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index 8072083ff65..3e9d49f38b5 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -302,13 +302,7 @@ private module Cached { or n instanceof PostUpdateNodes::ExprPostUpdateNode or - // TODO: Explain why SynthReturnNode is needed! - // if we don't include this, we are not able to find this call: - // https://github.com/github/codeql/blob/976daddd36a63bf46836d141d04172e90bb4b33c/ruby/ql/test/library-tests/frameworks/http_clients/NetHttp.rb#L24 - n instanceof SynthReturnNode - or - // Expressions that can't be reached from another entry definition or expression. - n instanceof ExprNode and + // Nodes that can't be reached from another entry definition or expression. not localFlowStepTypeTracker+(any(Node n0 | n0 instanceof ExprNode or From d5d1eb717d1eff3d875484b8af8f61d7826c291f Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Wed, 4 May 2022 18:13:54 +0200 Subject: [PATCH 122/171] Swift: add structured C++ generated classes This adds `cppgen`, creating structured C++ classes mirroring QL classes out of `schema.yml`. An example of generated code at the time of this commit can be found [in this gist][1]. [1]: https://gist.github.com/redsun82/57304ddb487a8aa40eaa0caa695048fa Closes https://github.com/github/codeql-c-team/issues/863 --- swift/codegen/BUILD.bazel | 23 ++++ swift/codegen/cppgen.py | 67 +++++++++ swift/codegen/lib/cpp.py | 68 +++++++++- swift/codegen/lib/options.py | 2 +- swift/codegen/templates/BUILD.bazel | 8 +- swift/codegen/templates/cpp_classes.mustache | 46 +++++++ .../{cpp_tags.mustache => trap_tags.mustache} | 0 ...cpp_traps.mustache => trap_traps.mustache} | 0 swift/codegen/test/test_cpp.py | 57 +++++++- swift/codegen/test/test_cppgen.py | 127 ++++++++++++++++++ swift/codegen/test/test_dbscheme.py | 2 +- swift/codegen/test/test_dbschemegen.py | 2 +- swift/codegen/test/test_ql.py | 2 +- swift/codegen/test/test_qlgen.py | 2 +- swift/codegen/test/test_render.py | 2 +- swift/codegen/test/test_schema.py | 2 +- swift/codegen/test/test_trapgen.py | 32 ++--- swift/codegen/trapgen.py | 27 +--- swift/extractor/SwiftExtractor.cpp | 9 +- swift/extractor/trap/BUILD.bazel | 22 ++- swift/extractor/trap/TrapLabel.h | 5 + 21 files changed, 445 insertions(+), 60 deletions(-) create mode 100644 swift/codegen/cppgen.py create mode 100644 swift/codegen/templates/cpp_classes.mustache rename swift/codegen/templates/{cpp_tags.mustache => trap_tags.mustache} (100%) rename swift/codegen/templates/{cpp_traps.mustache => trap_traps.mustache} (100%) create mode 100644 swift/codegen/test/test_cppgen.py diff --git a/swift/codegen/BUILD.bazel b/swift/codegen/BUILD.bazel index 3eac41e90ea..5b2a86f0e0b 100644 --- a/swift/codegen/BUILD.bazel +++ b/swift/codegen/BUILD.bazel @@ -1,5 +1,17 @@ load("@swift_codegen_deps//:requirements.bzl", "requirement") +filegroup( + name = "schema", + srcs = ["schema.yml"], + visibility = ["//swift:__subpackages__"], +) + +filegroup( + name = "schema_includes", + srcs = glob(["*.dbscheme"]), + visibility = ["//swift:__subpackages__"], +) + py_binary( name = "codegen", srcs = glob( @@ -15,6 +27,17 @@ py_binary( py_binary( name = "trapgen", srcs = ["trapgen.py"], + data = ["//swift/codegen/templates:trap"], + visibility = ["//swift:__subpackages__"], + deps = [ + "//swift/codegen/lib", + requirement("toposort"), + ], +) + +py_binary( + name = "cppgen", + srcs = ["cppgen.py"], data = ["//swift/codegen/templates:cpp"], visibility = ["//swift:__subpackages__"], deps = [ diff --git a/swift/codegen/cppgen.py b/swift/codegen/cppgen.py new file mode 100644 index 00000000000..6eeec931fae --- /dev/null +++ b/swift/codegen/cppgen.py @@ -0,0 +1,67 @@ +import functools +import inflection +from typing import Dict + +from toposort import toposort_flatten + +from swift.codegen.lib import cpp, generator, schema + + +def _get_type(t: str) -> str: + if t == "string": + return "std::string" + if t == "boolean": + return "bool" + if t[0].isupper(): + return f"TrapLabel<{t}Tag>" + return t + + +def _get_field(cls: schema.Class, p: schema.Property) -> cpp.Field: + trap_name = None + if not p.is_single: + trap_name = inflection.pluralize(inflection.camelize(f"{cls.name}_{p.name}")) + "Trap" + args = dict( + name=p.name + ("_" if p.name in cpp.cpp_keywords else ""), + type=_get_type(p.type), + is_optional=p.is_optional, + is_repeated=p.is_repeated, + trap_name=trap_name, + ) + args.update(cpp.get_field_override(p.name)) + return cpp.Field(**args) + + +class Processor: + def __init__(self, data: Dict[str, schema.Class]): + self._classmap = data + + @functools.cache + def _get_class(self, name: str) -> cpp.Class: + cls = self._classmap[name] + trap_name = None + if not cls.derived or any(p.is_single for p in cls.properties): + trap_name = inflection.pluralize(cls.name) + "Trap" + return cpp.Class( + name=name, + bases=[self._get_class(b) for b in cls.bases], + fields=[_get_field(cls, p) for p in cls.properties], + final=not cls.derived, + trap_name=trap_name, + ) + + def get_classes(self): + inheritance_graph = {k: cls.bases for k, cls in self._classmap.items()} + return [self._get_class(cls) for cls in toposort_flatten(inheritance_graph)] + + +def generate(opts, renderer): + processor = Processor({cls.name: cls for cls in schema.load(opts.schema).classes}) + out = opts.cpp_output + renderer.render(cpp.ClassList(processor.get_classes()), out / "TrapClasses.h") + + +tags = ("cpp", "schema") + +if __name__ == "__main__": + generator.run() diff --git a/swift/codegen/lib/cpp.py b/swift/codegen/lib/cpp.py index a933d09919c..89069a58239 100644 --- a/swift/codegen/lib/cpp.py +++ b/swift/codegen/lib/cpp.py @@ -1,3 +1,4 @@ +import re from dataclasses import dataclass, field from typing import List, ClassVar @@ -14,13 +15,35 @@ cpp_keywords = {"alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", " "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq"} +_field_overrides = [ + (re.compile(r"(start|end)_(line|column)|index|num_.*"), {"type": "unsigned"}), + (re.compile(r"(.*)_"), lambda m: {"name": m[1]}), +] + + +def get_field_override(field: str): + for r, o in _field_overrides: + m = r.fullmatch(field) + if m: + return o(m) if callable(o) else o + return {} + @dataclass class Field: name: str type: str + is_optional: bool = False + is_repeated: bool = False + trap_name: str = None first: bool = False + def __post_init__(self): + if self.is_optional: + self.type = f"std::optional<{self.type}>" + elif self.is_repeated: + self.type = f"std::vector<{self.type}>" + @property def cpp_name(self): if self.name in cpp_keywords: @@ -36,6 +59,12 @@ class Field: else: return lambda x: x + @property + def is_single(self): + return not (self.is_optional or self.is_repeated) + + + @dataclass class Trap: @@ -74,13 +103,48 @@ class Tag: @dataclass class TrapList: - template: ClassVar = 'cpp_traps' + template: ClassVar = 'trap_traps' traps: List[Trap] = field(default_factory=list) @dataclass class TagList: - template: ClassVar = 'cpp_tags' + template: ClassVar = 'trap_tags' tags: List[Tag] = field(default_factory=list) + + +@dataclass +class ClassBase: + ref: 'Class' + first: bool = False + + +@dataclass +class Class: + name: str + bases: List[ClassBase] = field(default_factory=list) + final: bool = False + fields: List[Field] = field(default_factory=list) + trap_name: str = None + + def __post_init__(self): + self.bases = [ClassBase(c) for c in sorted(self.bases, key=lambda cls: cls.name)] + if self.bases: + self.bases[0].first = True + + @property + def has_bases(self): + return bool(self.bases) + + @property + def single_fields(self): + return [f for f in self.fields if f.is_single] + + +@dataclass +class ClassList: + template: ClassVar = "cpp_classes" + + classes: List[Class] diff --git a/swift/codegen/lib/options.py b/swift/codegen/lib/options.py index 6332444b752..9dbc19355e0 100644 --- a/swift/codegen/lib/options.py +++ b/swift/codegen/lib/options.py @@ -15,7 +15,7 @@ def _init_options(): Option("--ql-output", tags=["ql"], type=_abspath, default=paths.swift_dir / "ql/lib/codeql/swift/generated") Option("--ql-stub-output", tags=["ql"], type=_abspath, default=paths.swift_dir / "ql/lib/codeql/swift/elements") Option("--codeql-binary", tags=["ql"], default="codeql") - Option("--trap-output", tags=["trap"], type=_abspath, required=True) + Option("--cpp-output", tags=["cpp"], type=_abspath, required=True) def _abspath(x): diff --git a/swift/codegen/templates/BUILD.bazel b/swift/codegen/templates/BUILD.bazel index 6e29f4d3a6a..7745e7ea2ac 100644 --- a/swift/codegen/templates/BUILD.bazel +++ b/swift/codegen/templates/BUILD.bazel @@ -1,5 +1,11 @@ +package(default_visibility = ["//swift:__subpackages__"]) + +filegroup( + name = "trap", + srcs = glob(["trap_*.mustache"]), +) + filegroup( name = "cpp", srcs = glob(["cpp_*.mustache"]), - visibility = ["//swift:__subpackages__"], ) diff --git a/swift/codegen/templates/cpp_classes.mustache b/swift/codegen/templates/cpp_classes.mustache new file mode 100644 index 00000000000..88329bdcd5b --- /dev/null +++ b/swift/codegen/templates/cpp_classes.mustache @@ -0,0 +1,46 @@ +// generated by {{generator}} +// clang-format off +#pragma once + +#include +#include +#include + +#include "swift/extractor/trap/TrapLabel.h" +#include "swift/extractor/trap/TrapEntries.h" + +namespace codeql { +{{#classes}} + +struct {{name}}{{#final}} : Binding<{{name}}Tag>{{#bases}}, {{ref.name}}{{/bases}}{{/final}}{{^final}}{{#has_bases}}: {{#bases}}{{^first}}, {{/first}}{{ref.name}}{{/bases}}{{/has_bases}}{{/final}} { + {{#fields}} + {{type}} {{name}}{}; + {{/fields}} + {{#final}} + + friend std::ostream& operator<<(std::ostream& out, const {{name}}& x) { + x.emit(out); + return out; + } + {{/final}} + + protected: + void emit({{^final}}TrapLabel<{{name}}Tag> id, {{/final}}std::ostream& out) const { + {{#bases}} + {{ref.name}}::emit(id, out); + {{/bases}} + {{#trap_name}} + out << {{.}}{id{{#single_fields}}, {{name}}{{/single_fields}}} << '\n'; + {{/trap_name}} + {{#fields}} + {{#is_optional}} + if ({{name}}) out << {{trap_name}}{id, *{{name}}} << '\n'; + {{/is_optional}} + {{#is_repeated}} + for (auto i = 0u; i < {{name}}.size(); ++i) out << {{trap_name}}{id, i, {{name}}[i]}; + {{/is_repeated}} + {{/fields}} + } +}; +{{/classes}} +} diff --git a/swift/codegen/templates/cpp_tags.mustache b/swift/codegen/templates/trap_tags.mustache similarity index 100% rename from swift/codegen/templates/cpp_tags.mustache rename to swift/codegen/templates/trap_tags.mustache diff --git a/swift/codegen/templates/cpp_traps.mustache b/swift/codegen/templates/trap_traps.mustache similarity index 100% rename from swift/codegen/templates/cpp_traps.mustache rename to swift/codegen/templates/trap_traps.mustache diff --git a/swift/codegen/test/test_cpp.py b/swift/codegen/test/test_cpp.py index 8b4ff5acba7..0368831d453 100644 --- a/swift/codegen/test/test_cpp.py +++ b/swift/codegen/test/test_cpp.py @@ -27,6 +27,27 @@ def test_field_get_streamer(type, expected): assert f.get_streamer()("value") == expected +@pytest.mark.parametrize("is_optional,is_repeated,expected", [ + (False, False, True), + (True, False, False), + (False, True, False), + (True, True, False), +]) +def test_field_is_single(is_optional, is_repeated, expected): + f = cpp.Field("name", "type", is_optional=is_optional, is_repeated=is_repeated) + assert f.is_single is expected + + +@pytest.mark.parametrize("is_optional,is_repeated,expected", [ + (False, False, "bar"), + (True, False, "std::optional"), + (False, True, "std::vector"), +]) +def test_field_modal_types(is_optional, is_repeated, expected): + f = cpp.Field("name", "bar", is_optional=is_optional, is_repeated=is_repeated) + assert f.type == expected + + def test_trap_has_first_field_marked(): fields = [ cpp.Field("a", "x"), @@ -56,5 +77,39 @@ def test_tag_has_bases(bases, expected): assert t.has_bases is expected +def test_class_has_first_base_marked(): + bases = [ + cpp.Class("a"), + cpp.Class("b"), + cpp.Class("c"), + ] + expected = [cpp.ClassBase(c) for c in bases] + expected[0].first = True + c = cpp.Class("foo", bases=bases) + assert c.bases == expected + + +@pytest.mark.parametrize("bases,expected", [ + ([], False), + (["a"], True), + (["a", "b"], True) +]) +def test_class_has_bases(bases, expected): + t = cpp.Class("name", [cpp.Class(b) for b in bases]) + assert t.has_bases is expected + + +def test_class_single_fields(): + fields = [ + cpp.Field("a", "A"), + cpp.Field("b", "B", is_optional=True), + cpp.Field("c", "C"), + cpp.Field("d", "D", is_repeated=True), + cpp.Field("e", "E"), + ] + c = cpp.Class("foo", fields=fields) + assert c.single_fields == fields[::2] + + if __name__ == '__main__': - sys.exit(pytest.main()) + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/test/test_cppgen.py b/swift/codegen/test/test_cppgen.py new file mode 100644 index 00000000000..c5a759bbbf8 --- /dev/null +++ b/swift/codegen/test/test_cppgen.py @@ -0,0 +1,127 @@ +import sys + +from swift.codegen import cppgen +from swift.codegen.lib import cpp +from swift.codegen.test.utils import * + +output_dir = pathlib.Path("path", "to", "output") + + +@pytest.fixture +def generate(opts, renderer, input): + opts.cpp_output = output_dir + + def ret(classes): + input.classes = classes + generated = run_generation(cppgen.generate, opts, renderer) + assert set(generated) == {output_dir / "TrapClasses.h"} + generated = generated[output_dir / "TrapClasses.h"] + assert isinstance(generated, cpp.ClassList) + return generated.classes + + return ret + + +def test_empty(generate): + assert generate([]) == [] + + +def test_empty_class(generate): + assert generate([ + schema.Class(name="MyClass"), + ]) == [ + cpp.Class(name="MyClass", final=True, trap_name="MyClassesTrap") + ] + + +def test_two_class_hierarchy(generate): + base = cpp.Class(name="A") + assert generate([ + schema.Class(name="A", derived={"B"}), + schema.Class(name="B", bases={"A"}), + ]) == [ + base, + cpp.Class(name="B", bases=[base], final=True, trap_name="BsTrap"), + ] + + +def test_complex_hierarchy_topologically_ordered(generate): + a = cpp.Class(name="A") + b = cpp.Class(name="B") + c = cpp.Class(name="C", bases=[a]) + d = cpp.Class(name="D", bases=[a]) + e = cpp.Class(name="E", bases=[b, c, d], final=True, trap_name="EsTrap") + f = cpp.Class(name="F", bases=[c], final=True, trap_name="FsTrap") + assert generate([ + schema.Class(name="F", bases={"C"}), + schema.Class(name="B", derived={"E"}), + schema.Class(name="D", bases={"A"}, derived={"E"}), + schema.Class(name="C", bases={"A"}, derived={"E", "F"}), + schema.Class(name="E", bases={"B", "C", "D"}), + schema.Class(name="A", derived={"C", "D"}), + ]) == [a, b, c, d, e, f] + + +@pytest.mark.parametrize("type,expected", [ + ("a", "a"), + ("string", "std::string"), + ("boolean", "bool"), + ("MyClass", "TrapLabel"), +]) +@pytest.mark.parametrize("property_cls,optional,repeated,trap_name", [ + (schema.SingleProperty, False, False, None), + (schema.OptionalProperty, True, False, "MyClassPropsTrap"), + (schema.RepeatedProperty, False, True, "MyClassPropsTrap"), +]) +def test_class_with_field(generate, type, expected, property_cls, optional, repeated, trap_name): + assert generate([ + schema.Class(name="MyClass", properties=[property_cls("prop", type)]), + ]) == [ + cpp.Class(name="MyClass", + fields=[cpp.Field("prop", expected, is_optional=optional, + is_repeated=repeated, trap_name=trap_name)], + trap_name="MyClassesTrap", + final=True) + ] + + +@pytest.mark.parametrize("name", ["start_line", "start_column", "end_line", "end_column", "index", "num_whatever"]) +def test_class_with_overridden_unsigned_field(generate, name): + assert generate([ + schema.Class(name="MyClass", properties=[ + schema.SingleProperty(name, "bar")]), + ]) == [ + cpp.Class(name="MyClass", + fields=[cpp.Field(name, "unsigned")], + trap_name="MyClassesTrap", + final=True) + ] + + +def test_class_with_overridden_underscore_field(generate): + assert generate([ + schema.Class(name="MyClass", properties=[ + schema.SingleProperty("something_", "bar")]), + ]) == [ + cpp.Class(name="MyClass", + fields=[cpp.Field("something", "bar")], + trap_name="MyClassesTrap", + final=True) + ] + + +@pytest.mark.parametrize("name", cpp.cpp_keywords) +def test_class_with_keyword_field(generate, name): + assert generate([ + schema.Class(name="MyClass", properties=[ + schema.SingleProperty(name, "bar")]), + ]) == [ + cpp.Class(name="MyClass", + fields=[cpp.Field(name + "_", "bar")], + trap_name="MyClassesTrap", + final=True) + ] + + +if __name__ == '__main__': + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/test/test_dbscheme.py b/swift/codegen/test/test_dbscheme.py index c67225e4303..9eaca07bd51 100644 --- a/swift/codegen/test/test_dbscheme.py +++ b/swift/codegen/test/test_dbscheme.py @@ -151,4 +151,4 @@ int ignored: int ref*/); if __name__ == '__main__': - sys.exit(pytest.main()) + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/test/test_dbschemegen.py b/swift/codegen/test/test_dbschemegen.py index d8f0089d863..97b0090cf74 100644 --- a/swift/codegen/test/test_dbschemegen.py +++ b/swift/codegen/test/test_dbschemegen.py @@ -304,4 +304,4 @@ def test_class_with_derived_and_repeated_property(opts, input, renderer): if __name__ == '__main__': - sys.exit(pytest.main()) + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/test/test_ql.py b/swift/codegen/test/test_ql.py index 8127a03073e..44da8b560f9 100644 --- a/swift/codegen/test/test_ql.py +++ b/swift/codegen/test/test_ql.py @@ -97,4 +97,4 @@ def test_non_root_class(): if __name__ == '__main__': - sys.exit(pytest.main()) + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/test/test_qlgen.py b/swift/codegen/test/test_qlgen.py index 94cd6641afc..a81c8600c57 100644 --- a/swift/codegen/test/test_qlgen.py +++ b/swift/codegen/test/test_qlgen.py @@ -195,4 +195,4 @@ def test_empty_cleanup(opts, input, renderer, tmp_path): if __name__ == '__main__': - sys.exit(pytest.main()) + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/test/test_render.py b/swift/codegen/test/test_render.py index c900cfa99e6..ea007a54563 100644 --- a/swift/codegen/test/test_render.py +++ b/swift/codegen/test/test_render.py @@ -76,4 +76,4 @@ def test_cleanup(sut): if __name__ == '__main__': - sys.exit(pytest.main()) + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/test/test_schema.py b/swift/codegen/test/test_schema.py index 9b52bcbbaa1..b7376407c20 100644 --- a/swift/codegen/test/test_schema.py +++ b/swift/codegen/test/test_schema.py @@ -152,4 +152,4 @@ A: if __name__ == '__main__': - sys.exit(pytest.main()) + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/test/test_trapgen.py b/swift/codegen/test/test_trapgen.py index 089a809210f..5ac6cd3718c 100644 --- a/swift/codegen/test/test_trapgen.py +++ b/swift/codegen/test/test_trapgen.py @@ -9,7 +9,7 @@ output_dir = pathlib.Path("path", "to", "output") @pytest.fixture def generate(opts, renderer, dbscheme_input): - opts.trap_output = output_dir + opts.cpp_output = output_dir def ret(entities): dbscheme_input.entities = entities @@ -105,28 +105,22 @@ def test_one_table_special_types(generate_traps, column, field): ] -@pytest.mark.parametrize("table,name,column,field", [ - ("locations", "Locations", dbscheme.Column( - "startWhatever", "bar"), cpp.Field("startWhatever", "unsigned")), - ("locations", "Locations", dbscheme.Column( - "endWhatever", "bar"), cpp.Field("endWhatever", "unsigned")), - ("foos", "Foos", dbscheme.Column("startWhatever", "bar"), - cpp.Field("startWhatever", "bar")), - ("foos", "Foos", dbscheme.Column("endWhatever", "bar"), - cpp.Field("endWhatever", "bar")), - ("foos", "Foos", dbscheme.Column("index", "bar"), cpp.Field("index", "unsigned")), - ("foos", "Foos", dbscheme.Column("num_whatever", "bar"), - cpp.Field("num_whatever", "unsigned")), - ("foos", "Foos", dbscheme.Column("whatever_", "bar"), cpp.Field("whatever", "bar")), -]) -def test_one_table_overridden_fields(generate_traps, table, name, column, field): +@pytest.mark.parametrize("name", ["start_line", "start_column", "end_line", "end_column", "index", "num_whatever"]) +def test_one_table_overridden_unsigned_field(generate_traps, name): assert generate_traps([ - dbscheme.Table(name=table, columns=[column]), + dbscheme.Table(name="foos", columns=[dbscheme.Column(name, "bar")]), ]) == [ - cpp.Trap(table, name=name, fields=[field]), + cpp.Trap("foos", name="Foos", fields=[cpp.Field(name, "unsigned")]), ] +def test_one_table_overridden_underscore_named_field(generate_traps): + assert generate_traps([ + dbscheme.Table(name="foos", columns=[dbscheme.Column("whatever_", "bar")]), + ]) == [ + cpp.Trap("foos", name="Foos", fields=[cpp.Field("whatever", "bar")]), + ] + def test_one_table_no_tags(generate_tags): assert generate_tags([ dbscheme.Table(name="foos", columns=[dbscheme.Column("bla", "int")]), @@ -160,4 +154,4 @@ def test_multiple_union_tags(generate_tags): if __name__ == '__main__': - sys.exit(pytest.main()) + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/trapgen.py b/swift/codegen/trapgen.py index 732354c8f9c..555b5bf9fdb 100755 --- a/swift/codegen/trapgen.py +++ b/swift/codegen/trapgen.py @@ -1,36 +1,17 @@ #!/usr/bin/env python3 import logging -import os import re -import sys import inflection from toposort import toposort_flatten -sys.path.append(os.path.dirname(__file__)) +from swift.codegen.lib import dbscheme, generator, cpp -from swift.codegen.lib import paths, dbscheme, generator, cpp - -field_overrides = [ - (re.compile(r"locations.*::(start|end).*|.*::(index|num_.*)"), {"type": "unsigned"}), - (re.compile(r".*::(.*)_"), lambda m: {"name": m[1]}), -] log = logging.getLogger(__name__) -def get_field_override(table, field): - spec = f"{table}::{field}" - for r, o in field_overrides: - m = r.fullmatch(spec) - if m and callable(o): - return o(m) - elif m: - return o - return {} - - def get_tag_name(s): assert s.startswith("@") return inflection.camelize(s[1:]) @@ -52,7 +33,7 @@ def get_field(c: dbscheme.Column, table: str): "name": c.schema_name, "type": c.type, } - args.update(get_field_override(table, c.schema_name)) + args.update(cpp.get_field_override(c.schema_name)) args["type"] = get_cpp_type(args["type"]) return cpp.Field(**args) @@ -78,7 +59,7 @@ def get_trap(t: dbscheme.Table): def generate(opts, renderer): tag_graph = {} - out = opts.trap_output + out = opts.cpp_output traps = [] for e in dbscheme.iterload(opts.dbscheme): @@ -102,7 +83,7 @@ def generate(opts, renderer): renderer.render(cpp.TagList(tags), out / "TrapTags.h") -tags = ("trap", "dbscheme") +tags = ("cpp", "dbscheme") if __name__ == "__main__": generator.run() diff --git a/swift/extractor/SwiftExtractor.cpp b/swift/extractor/SwiftExtractor.cpp index 7413763aaba..fd87cee6e54 100644 --- a/swift/extractor/SwiftExtractor.cpp +++ b/swift/extractor/SwiftExtractor.cpp @@ -12,7 +12,7 @@ #include #include -#include "swift/extractor/trap/TrapEntries.h" +#include "swift/extractor/trap/TrapClasses.h" using namespace codeql; @@ -75,9 +75,10 @@ static void extractFile(const SwiftExtractorConfiguration& config, swift::Source } trap << "\n\n"; - TrapLabel label{}; - trap << label << "=*\n"; - trap << FilesTrap{label, srcFilePath.str().str()} << "\n"; + File f; + f.id = TrapLabel{}; + f.name = srcFilePath.str().str(); + trap << f.id << "=*\n" << f; // TODO: Pick a better name to avoid collisions std::string trapName = file.getFilename().str() + ".trap"; diff --git a/swift/extractor/trap/BUILD.bazel b/swift/extractor/trap/BUILD.bazel index eecf5a07e53..7fa90c89e91 100644 --- a/swift/extractor/trap/BUILD.bazel +++ b/swift/extractor/trap/BUILD.bazel @@ -1,16 +1,32 @@ genrule( - name = "gen", + name = "trapgen", srcs = ["//swift:dbscheme"], outs = [ "TrapEntries.h", "TrapTags.h", ], - cmd = "$(location //swift/codegen:trapgen) --dbscheme $< --trap-output $(RULEDIR)", + cmd = "$(location //swift/codegen:trapgen) --dbscheme $< --cpp-output $(RULEDIR)", exec_tools = ["//swift/codegen:trapgen"], ) +genrule( + name = "cppgen", + srcs = [ + "//swift/codegen:schema", + "//swift/codegen:schema_includes", + ], + outs = [ + "TrapClasses.h", + ], + cmd = "$(location //swift/codegen:cppgen) --schema $(location //swift/codegen:schema) --cpp-output $(RULEDIR)", + exec_tools = ["//swift/codegen:cppgen"], +) + cc_library( name = "trap", - hdrs = glob(["*.h"]) + [":gen"], + hdrs = glob(["*.h"]) + [ + ":trapgen", + ":cppgen", + ], visibility = ["//visibility:public"], ) diff --git a/swift/extractor/trap/TrapLabel.h b/swift/extractor/trap/TrapLabel.h index 62a574e4ff9..9928bb9a2b9 100644 --- a/swift/extractor/trap/TrapLabel.h +++ b/swift/extractor/trap/TrapLabel.h @@ -54,6 +54,11 @@ inline auto trapQuoted(const std::string& s) { return std::quoted(s, '"', '"'); } +template +struct Binding { + TrapLabel id; +}; + } // namespace codeql namespace std { From c2d3aac3495b5f352b0949ceff975f22af66b2e9 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 5 May 2022 09:48:07 +0200 Subject: [PATCH 123/171] Swift: fix no functools.cache in python 3.8 --- swift/codegen/cppgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/codegen/cppgen.py b/swift/codegen/cppgen.py index 6eeec931fae..bbd65368e6f 100644 --- a/swift/codegen/cppgen.py +++ b/swift/codegen/cppgen.py @@ -36,7 +36,7 @@ class Processor: def __init__(self, data: Dict[str, schema.Class]): self._classmap = data - @functools.cache + @functools.lru_cache(maxsize=None) def _get_class(self, name: str) -> cpp.Class: cls = self._classmap[name] trap_name = None From 9798d8ba26eede8a4b4de2f0a6331aa66a6b6e5b Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 5 May 2022 11:50:12 +0200 Subject: [PATCH 124/171] Swift: add `?*` modifier to schema specification This indicates a list of optional entries. This is different than simply repeatind entries because of the indexing. --- swift/codegen/dbschemegen.py | 20 ++++++++-------- swift/codegen/lib/cpp.py | 2 +- swift/codegen/lib/ql.py | 5 ++++ swift/codegen/lib/schema.py | 11 ++++++++- swift/codegen/qlgen.py | 16 +++++++------ swift/codegen/schema.yml | 2 +- swift/codegen/templates/cpp_classes.mustache | 11 ++++++++- swift/codegen/templates/ql_class.mustache | 24 +++++++++---------- swift/codegen/test/test_cpp.py | 1 + swift/codegen/test/test_cppgen.py | 1 + swift/codegen/test/test_dbschemegen.py | 19 +++++++++++---- swift/codegen/test/test_ql.py | 10 ++++++++ swift/codegen/test/test_qlgen.py | 17 ++++++++++++- swift/codegen/test/test_schema.py | 2 ++ .../generated/decl/PatternBindingDecl.qll | 2 -- 15 files changed, 103 insertions(+), 40 deletions(-) diff --git a/swift/codegen/dbschemegen.py b/swift/codegen/dbschemegen.py index 1b68262ad22..c99cec1ea29 100755 --- a/swift/codegen/dbschemegen.py +++ b/swift/codegen/dbschemegen.py @@ -38,16 +38,7 @@ def cls_to_dbscheme(cls: schema.Class): ) # use property-specific tables for 1-to-many and 1-to-at-most-1 properties for f in cls.properties: - if f.is_optional: - yield Table( - keyset=KeySet(["id"]), - name=inflection.tableize(f"{cls.name}_{f.name}"), - columns=[ - Column("id", type=dbtype(cls.name)), - Column(f.name, dbtype(f.type)), - ], - ) - elif f.is_repeated: + if f.is_repeated: yield Table( keyset=KeySet(["id", "index"]), name=inflection.tableize(f"{cls.name}_{f.name}"), @@ -57,6 +48,15 @@ def cls_to_dbscheme(cls: schema.Class): Column(inflection.singularize(f.name), dbtype(f.type)), ] ) + elif f.is_optional: + yield Table( + keyset=KeySet(["id"]), + name=inflection.tableize(f"{cls.name}_{f.name}"), + columns=[ + Column("id", type=dbtype(cls.name)), + Column(f.name, dbtype(f.type)), + ], + ) def get_declarations(data: schema.Schema): diff --git a/swift/codegen/lib/cpp.py b/swift/codegen/lib/cpp.py index 89069a58239..9395121ff5a 100644 --- a/swift/codegen/lib/cpp.py +++ b/swift/codegen/lib/cpp.py @@ -41,7 +41,7 @@ class Field: def __post_init__(self): if self.is_optional: self.type = f"std::optional<{self.type}>" - elif self.is_repeated: + if self.is_repeated: self.type = f"std::vector<{self.type}>" @property diff --git a/swift/codegen/lib/ql.py b/swift/codegen/lib/ql.py index 9fa4e02a42e..0b80757c96f 100644 --- a/swift/codegen/lib/ql.py +++ b/swift/codegen/lib/ql.py @@ -22,6 +22,7 @@ class Property: params: List[Param] = field(default_factory=list) first: bool = False local_var: str = "x" + is_optional: bool = False def __post_init__(self): if self.params: @@ -43,6 +44,10 @@ class Property: def type_is_class(self): return self.type[0].isupper() + @property + def is_repeated(self): + return bool(self.plural) + @dataclass class Class: diff --git a/swift/codegen/lib/schema.py b/swift/codegen/lib/schema.py index 5871c90ed3b..06ceb4b63bb 100644 --- a/swift/codegen/lib/schema.py +++ b/swift/codegen/lib/schema.py @@ -35,6 +35,12 @@ class RepeatedProperty(Property): is_repeated: ClassVar = True +@dataclass +class RepeatedOptionalProperty(Property): + is_optional: ClassVar = True + is_repeated: ClassVar = True + + @dataclass class Class: name: str @@ -51,7 +57,10 @@ class Schema: def _parse_property(name, type): - if type.endswith("*"): + if type.endswith("?*"): + cls = RepeatedOptionalProperty + type = type[:-2] + elif type.endswith("*"): cls = RepeatedProperty type = type[:-1] elif type.endswith("?"): diff --git a/swift/codegen/qlgen.py b/swift/codegen/qlgen.py index b16bd38a208..77e037ee5fe 100755 --- a/swift/codegen/qlgen.py +++ b/swift/codegen/qlgen.py @@ -18,13 +18,6 @@ def get_ql_property(cls: schema.Class, prop: schema.Property): tablename=inflection.tableize(cls.name), tableparams=["this"] + ["result" if p is prop else "_" for p in cls.properties if p.is_single], ) - elif prop.is_optional: - return ql.Property( - singular=inflection.camelize(prop.name), - type=prop.type, - tablename=inflection.tableize(f"{cls.name}_{prop.name}"), - tableparams=["this", "result"], - ) elif prop.is_repeated: return ql.Property( singular=inflection.singularize(inflection.camelize(prop.name)), @@ -33,6 +26,15 @@ def get_ql_property(cls: schema.Class, prop: schema.Property): tablename=inflection.tableize(f"{cls.name}_{prop.name}"), tableparams=["this", "index", "result"], params=[ql.Param("index", type="int")], + is_optional=prop.is_optional, + ) + elif prop.is_optional: + return ql.Property( + singular=inflection.camelize(prop.name), + type=prop.type, + tablename=inflection.tableize(f"{cls.name}_{prop.name}"), + tableparams=["this", "result"], + is_optional=True, ) diff --git a/swift/codegen/schema.yml b/swift/codegen/schema.yml index 6e07edbe2e5..4ea4a8190a6 100644 --- a/swift/codegen/schema.yml +++ b/swift/codegen/schema.yml @@ -256,7 +256,7 @@ OperatorDecl: PatternBindingDecl: _extends: Decl - inits: Expr* + inits: Expr?* patterns: Pattern* PoundDiagnosticDecl: diff --git a/swift/codegen/templates/cpp_classes.mustache b/swift/codegen/templates/cpp_classes.mustache index 88329bdcd5b..504ca92934b 100644 --- a/swift/codegen/templates/cpp_classes.mustache +++ b/swift/codegen/templates/cpp_classes.mustache @@ -34,10 +34,19 @@ struct {{name}}{{#final}} : Binding<{{name}}Tag>{{#bases}}, {{ref.name}}{{/bases {{/trap_name}} {{#fields}} {{#is_optional}} + {{^is_repeated}} if ({{name}}) out << {{trap_name}}{id, *{{name}}} << '\n'; + {{/is_repeated}} {{/is_optional}} {{#is_repeated}} - for (auto i = 0u; i < {{name}}.size(); ++i) out << {{trap_name}}{id, i, {{name}}[i]}; + for (auto i = 0u; i < {{name}}.size(); ++i) { + {{^is_optional}} + out << {{trap_name}}{id, i, {{name}}[i]}; + {{/is_optional}} + {{#is_optional}} + if ({{name}}[i]) out << {{trap_name}}{id, i, *{{name}}[i]}; + {{/is_optional}} + } {{/is_repeated}} {{/fields}} } diff --git a/swift/codegen/templates/ql_class.mustache b/swift/codegen/templates/ql_class.mustache index f04914bd39d..e2f2a6a449f 100644 --- a/swift/codegen/templates/ql_class.mustache +++ b/swift/codegen/templates/ql_class.mustache @@ -20,28 +20,28 @@ class {{name}}Base extends {{db_id}}{{#bases}}, {{.}}{{/bases}} { {{/final}} {{#properties}} - {{#type_is_class}} - {{type}} get{{singular}}({{#params}}{{^first}}, {{/first}}{{type}} {{param}}{{/params}}) { + {{type}} get{{singular}}({{#is_repeated}}int index{{/is_repeated}}) { + {{#type_is_class}} exists({{type}} {{local_var}} | {{tablename}}({{#tableparams}}{{^first}}, {{/first}}{{param}}{{/tableparams}}) and result = {{local_var}}.resolve()) - } - {{/type_is_class}} - {{^type_is_class}} - {{type}} get{{singular}}({{#params}}{{^first}}, {{/first}}{{type}} {{param}}{{/params}}) { + {{/type_is_class}} + {{^type_is_class}} {{tablename}}({{#tableparams}}{{^first}}, {{/first}}{{param}}{{/tableparams}}) + {{/type_is_class}} } - {{/type_is_class}} - {{#indefinite_article}} + {{#is_repeated}} - {{type}} get{{.}}{{singular}}() { - result = get{{singular}}({{#params}}{{^first}}, {{/first}}_{{/params}}) + {{type}} get{{indefinite_article}}{{singular}}() { + result = get{{singular}}(_) } + {{^is_optional}} int getNumberOf{{plural}}() { - result = count(get{{.}}{{singular}}()) + result = count(get{{indefinite_article}}{{singular}}()) } - {{/indefinite_article}} + {{/is_optional}} + {{/is_repeated}} {{/properties}} } diff --git a/swift/codegen/test/test_cpp.py b/swift/codegen/test/test_cpp.py index 0368831d453..74dbc2d2182 100644 --- a/swift/codegen/test/test_cpp.py +++ b/swift/codegen/test/test_cpp.py @@ -42,6 +42,7 @@ def test_field_is_single(is_optional, is_repeated, expected): (False, False, "bar"), (True, False, "std::optional"), (False, True, "std::vector"), + (True, True, "std::vector>"), ]) def test_field_modal_types(is_optional, is_repeated, expected): f = cpp.Field("name", "bar", is_optional=is_optional, is_repeated=is_repeated) diff --git a/swift/codegen/test/test_cppgen.py b/swift/codegen/test/test_cppgen.py index c5a759bbbf8..1dbb6b61bfe 100644 --- a/swift/codegen/test/test_cppgen.py +++ b/swift/codegen/test/test_cppgen.py @@ -72,6 +72,7 @@ def test_complex_hierarchy_topologically_ordered(generate): (schema.SingleProperty, False, False, None), (schema.OptionalProperty, True, False, "MyClassPropsTrap"), (schema.RepeatedProperty, False, True, "MyClassPropsTrap"), + (schema.RepeatedOptionalProperty, True, True, "MyClassPropsTrap"), ]) def test_class_with_field(generate, type, expected, property_cls, optional, repeated, trap_name): assert generate([ diff --git a/swift/codegen/test/test_dbschemegen.py b/swift/codegen/test/test_dbschemegen.py index 97b0090cf74..82521fb9892 100644 --- a/swift/codegen/test/test_dbschemegen.py +++ b/swift/codegen/test/test_dbschemegen.py @@ -126,10 +126,11 @@ def test_final_class_with_optional_field(opts, input, renderer): ) -def test_final_class_with_repeated_field(opts, input, renderer): +@pytest.mark.parametrize("property_cls", [schema.RepeatedProperty, schema.RepeatedOptionalProperty]) +def test_final_class_with_repeated_field(opts, input, renderer, property_cls): input.classes = [ schema.Class("Object", properties=[ - schema.RepeatedProperty("foo", "bar"), + property_cls("foo", "bar"), ]), ] assert generate(opts, renderer) == dbscheme.Scheme( @@ -161,7 +162,8 @@ def test_final_class_with_more_fields(opts, input, renderer): schema.SingleProperty("one", "x"), schema.SingleProperty("two", "y"), schema.OptionalProperty("three", "z"), - schema.RepeatedProperty("four", "w"), + schema.RepeatedProperty("four", "u"), + schema.RepeatedOptionalProperty("five", "v"), ]), ] assert generate(opts, renderer) == dbscheme.Scheme( @@ -190,7 +192,16 @@ def test_final_class_with_more_fields(opts, input, renderer): columns=[ dbscheme.Column('id', '@object'), dbscheme.Column('index', 'int'), - dbscheme.Column('four', 'w'), + dbscheme.Column('four', 'u'), + ] + ), + dbscheme.Table( + name="object_fives", + keyset=dbscheme.KeySet(["id", "index"]), + columns=[ + dbscheme.Column('id', '@object'), + dbscheme.Column('index', 'int'), + dbscheme.Column('five', 'v'), ] ), ], diff --git a/swift/codegen/test/test_ql.py b/swift/codegen/test/test_ql.py index 44da8b560f9..79e88c70049 100644 --- a/swift/codegen/test/test_ql.py +++ b/swift/codegen/test/test_ql.py @@ -59,6 +59,16 @@ def test_property_indefinite_article(name, expected_article): assert prop.indefinite_article == expected_article +@pytest.mark.parametrize("plural,expected", [ + (None, False), + ("", False), + ("X", True), +]) +def test_property_is_plural(plural, expected): + prop = ql.Property("foo", "Foo", "props", ["x"], plural=plural) + assert prop.is_repeated is expected + + def test_property_no_plural_no_indefinite_article(): prop = ql.Property("Prop", "Foo", "props", ["x"]) assert prop.indefinite_article is None diff --git a/swift/codegen/test/test_qlgen.py b/swift/codegen/test/test_qlgen.py index a81c8600c57..1db7dada723 100644 --- a/swift/codegen/test/test_qlgen.py +++ b/swift/codegen/test/test_qlgen.py @@ -107,7 +107,8 @@ def test_optional_property(opts, input, renderer): import_file(): ql.ImportList([stub_import_prefix + "MyObject"]), stub_path() / "MyObject.qll": ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), ql_output_path() / "MyObject.qll": ql.Class(name="MyObject", final=True, properties=[ - ql.Property(singular="Foo", type="bar", tablename="my_object_foos", tableparams=["this", "result"]), + ql.Property(singular="Foo", type="bar", tablename="my_object_foos", tableparams=["this", "result"], + is_optional=True), ]) } @@ -126,6 +127,20 @@ def test_repeated_property(opts, input, renderer): } +def test_repeated_optional_property(opts, input, renderer): + input.classes = [ + schema.Class("MyObject", properties=[schema.RepeatedOptionalProperty("foo", "bar")]), + ] + assert generate(opts, renderer) == { + import_file(): ql.ImportList([stub_import_prefix + "MyObject"]), + stub_path() / "MyObject.qll": ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + ql_output_path() / "MyObject.qll": ql.Class(name="MyObject", final=True, properties=[ + ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos", params=[index_param], + tableparams=["this", "index", "result"], is_optional=True), + ]) + } + + def test_single_class_property(opts, input, renderer): input.classes = [ schema.Class("MyObject", properties=[schema.SingleProperty("foo", "Bar")]), diff --git a/swift/codegen/test/test_schema.py b/swift/codegen/test/test_schema.py index b7376407c20..36367a76b1f 100644 --- a/swift/codegen/test/test_schema.py +++ b/swift/codegen/test/test_schema.py @@ -140,6 +140,7 @@ A: one: string two: int? three: bool* + four: x?* """) assert ret.classes == [ schema.Class(root_name, derived={'A'}), @@ -147,6 +148,7 @@ A: schema.SingleProperty('one', 'string'), schema.OptionalProperty('two', 'int'), schema.RepeatedProperty('three', 'bool'), + schema.RepeatedOptionalProperty('four', 'x'), ]), ] diff --git a/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll index fd83d330670..9d693c9f9c7 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll @@ -15,8 +15,6 @@ class PatternBindingDeclBase extends @pattern_binding_decl, Decl { Expr getAnInit() { result = getInit(_) } - int getNumberOfInits() { result = count(getAnInit()) } - Pattern getPattern(int index) { exists(Pattern x | pattern_binding_decl_patterns(this, index, x) and From c87fb4df535dbc18f375e907daeac5aac293a989 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 5 May 2022 12:01:13 +0200 Subject: [PATCH 125/171] Swift: remove now unused `ql.Property.params` --- swift/codegen/lib/ql.py | 6 ------ swift/codegen/qlgen.py | 3 --- swift/codegen/test/test_ql.py | 20 -------------------- swift/codegen/test/test_qlgen.py | 5 ++--- 4 files changed, 2 insertions(+), 32 deletions(-) diff --git a/swift/codegen/lib/ql.py b/swift/codegen/lib/ql.py index 0b80757c96f..ee9103fd990 100644 --- a/swift/codegen/lib/ql.py +++ b/swift/codegen/lib/ql.py @@ -8,7 +8,6 @@ import inflection @dataclass class Param: param: str - type: str = None first: bool = False @@ -19,16 +18,11 @@ class Property: tablename: str tableparams: List[Param] plural: str = None - params: List[Param] = field(default_factory=list) first: bool = False local_var: str = "x" is_optional: bool = False def __post_init__(self): - if self.params: - self.params[0].first = True - while self.local_var in (p.param for p in self.params): - self.local_var += "_" assert self.tableparams if self.type_is_class: self.tableparams = [x if x != "result" else self.local_var for x in self.tableparams] diff --git a/swift/codegen/qlgen.py b/swift/codegen/qlgen.py index 77e037ee5fe..26a5e2edcae 100755 --- a/swift/codegen/qlgen.py +++ b/swift/codegen/qlgen.py @@ -25,7 +25,6 @@ def get_ql_property(cls: schema.Class, prop: schema.Property): type=prop.type, tablename=inflection.tableize(f"{cls.name}_{prop.name}"), tableparams=["this", "index", "result"], - params=[ql.Param("index", type="int")], is_optional=prop.is_optional, ) elif prop.is_optional: @@ -58,8 +57,6 @@ def get_types_used_by(cls: ql.Class): yield b for p in cls.properties: yield p.type - for param in p.params: - yield param.type def get_classes_used_by(cls: ql.Class): diff --git a/swift/codegen/test/test_ql.py b/swift/codegen/test/test_ql.py index 79e88c70049..e87383695c6 100644 --- a/swift/codegen/test/test_ql.py +++ b/swift/codegen/test/test_ql.py @@ -5,31 +5,11 @@ from swift.codegen.lib import ql from swift.codegen.test.utils import * -def test_property_has_first_param_marked(): - params = [ql.Param("a", "x"), ql.Param("b", "y"), ql.Param("c", "z")] - expected = deepcopy(params) - expected[0].first = True - prop = ql.Property("Prop", "foo", "props", ["this"], params=params) - assert prop.params == expected - - def test_property_has_first_table_param_marked(): tableparams = ["a", "b", "c"] prop = ql.Property("Prop", "foo", "props", tableparams) assert prop.tableparams[0].first assert [p.param for p in prop.tableparams] == tableparams - assert all(p.type is None for p in prop.tableparams) - - -@pytest.mark.parametrize("params,expected_local_var", [ - (["a", "b", "c"], "x"), - (["a", "x", "c"], "x_"), - (["a", "x", "x_", "c"], "x__"), - (["a", "x", "x_", "x__"], "x___"), -]) -def test_property_local_var_avoids_params_collision(params, expected_local_var): - prop = ql.Property("Prop", "foo", "props", ["this"], params=[ql.Param(p) for p in params]) - assert prop.local_var == expected_local_var def test_property_not_a_class(): diff --git a/swift/codegen/test/test_qlgen.py b/swift/codegen/test/test_qlgen.py index 1db7dada723..8affd50fb7f 100644 --- a/swift/codegen/test/test_qlgen.py +++ b/swift/codegen/test/test_qlgen.py @@ -18,7 +18,6 @@ ql_output_path = lambda: paths.swift_dir / "ql/lib/other/path" import_file = lambda: stub_path().with_suffix(".qll") stub_import_prefix = "stub.path." gen_import_prefix = "other.path." -index_param = ql.Param("index", "int") def generate(opts, renderer, written=None): @@ -121,7 +120,7 @@ def test_repeated_property(opts, input, renderer): import_file(): ql.ImportList([stub_import_prefix + "MyObject"]), stub_path() / "MyObject.qll": ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), ql_output_path() / "MyObject.qll": ql.Class(name="MyObject", final=True, properties=[ - ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos", params=[index_param], + ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos", tableparams=["this", "index", "result"]), ]) } @@ -135,7 +134,7 @@ def test_repeated_optional_property(opts, input, renderer): import_file(): ql.ImportList([stub_import_prefix + "MyObject"]), stub_path() / "MyObject.qll": ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), ql_output_path() / "MyObject.qll": ql.Class(name="MyObject", final=True, properties=[ - ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos", params=[index_param], + ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos", tableparams=["this", "index", "result"], is_optional=True), ]) } From c4d597d60f96cf4b1a173646794746cc17360589 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 5 May 2022 12:58:44 +0200 Subject: [PATCH 126/171] JS: Enumerate type-tracking steps through global access paths --- .../dataflow/internal/StepSummary.qll | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll index 065bb1b75a8..460aa4f9ccc 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll @@ -56,6 +56,18 @@ private module Cached { exists(DataFlow::Node mid | pred.flowsTo(mid) | StepSummary::smallstep(mid, succ, summary)) } + pragma[nomagic] + private DataFlow::Node getAGlobalStepPredecessor(string global) { + result = AccessPath::getAnAssignmentTo(global) and + AccessPath::isAssignedInUniqueFile(global) + } + + pragma[nomagic] + private DataFlow::Node getAGlobalStepSuccessor(string global) { + result = AccessPath::getAReferenceTo(global) and + AccessPath::isAssignedInUniqueFile(global) + } + /** * INTERNAL: Use `TypeBackTracker.smallstep()` instead. */ @@ -106,20 +118,10 @@ private module Cached { SharedTypeTrackingStep::step(pred, succ) and summary = LevelStep() or - // Store to global access path - exists(string name | - pred = AccessPath::getAnAssignmentTo(name) and - AccessPath::isAssignedInUniqueFile(name) and - succ = DataFlow::globalAccessPathRootPseudoNode() and - summary = StoreStep(name) - ) - or - // Load from global access path - exists(string name | - succ = AccessPath::getAReferenceTo(name) and - AccessPath::isAssignedInUniqueFile(name) and - pred = DataFlow::globalAccessPathRootPseudoNode() and - summary = LoadStep(name) + summary = LevelStep() and + exists(string global | + pred = getAGlobalStepPredecessor(global) and + succ = getAGlobalStepSuccessor(global) ) or // Store to non-global access path From de6e2c95e796e6ebe96ab117ba29e6438fcf8147 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 5 May 2022 13:36:08 +0200 Subject: [PATCH 127/171] Data flow: Speedup `subpaths` predicate (take 2) --- .../csharp/dataflow/internal/DataFlowImpl.qll | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) 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 91390dcadf0..89a35b00fa6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } From d9d5372f289fe7344f313d05434ac4e877bc0f7c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 5 May 2022 13:36:26 +0200 Subject: [PATCH 128/171] Data flow: Sync files --- .../cpp/dataflow/internal/DataFlowImpl.qll | 18 +++++++++++------- .../cpp/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++++------- .../cpp/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++++------- .../cpp/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++++------- .../dataflow/internal/DataFlowImplLocal.qll | 18 +++++++++++------- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 18 +++++++++++------- .../cpp/ir/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++++------- .../cpp/ir/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++++------- .../cpp/ir/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++++------- .../csharp/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++++------- .../csharp/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++++------- .../csharp/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++++------- .../csharp/dataflow/internal/DataFlowImpl5.qll | 18 +++++++++++------- .../java/dataflow/internal/DataFlowImpl.qll | 18 +++++++++++------- .../java/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++++------- .../java/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++++------- .../java/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++++------- .../java/dataflow/internal/DataFlowImpl5.qll | 18 +++++++++++------- .../java/dataflow/internal/DataFlowImpl6.qll | 18 +++++++++++------- .../DataFlowImplForOnActivityResult.qll | 18 +++++++++++------- .../DataFlowImplForSerializability.qll | 18 +++++++++++------- .../dataflow/new/internal/DataFlowImpl.qll | 18 +++++++++++------- .../dataflow/new/internal/DataFlowImpl2.qll | 18 +++++++++++------- .../dataflow/new/internal/DataFlowImpl3.qll | 18 +++++++++++------- .../dataflow/new/internal/DataFlowImpl4.qll | 18 +++++++++++------- .../ruby/dataflow/internal/DataFlowImpl.qll | 18 +++++++++++------- .../ruby/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++++------- .../internal/DataFlowImplForLibraries.qll | 18 +++++++++++------- 28 files changed, 308 insertions(+), 196 deletions(-) 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 91390dcadf0..89a35b00fa6 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 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 @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 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 @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 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 @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 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 @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } 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 91390dcadf0..89a35b00fa6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 91390dcadf0..89a35b00fa6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 91390dcadf0..89a35b00fa6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 91390dcadf0..89a35b00fa6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 91390dcadf0..89a35b00fa6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 91390dcadf0..89a35b00fa6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll index 91390dcadf0..89a35b00fa6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll index 91390dcadf0..89a35b00fa6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll index 91390dcadf0..89a35b00fa6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index 91390dcadf0..89a35b00fa6 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll index 91390dcadf0..89a35b00fa6 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll index 91390dcadf0..89a35b00fa6 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll index 91390dcadf0..89a35b00fa6 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll index 91390dcadf0..89a35b00fa6 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll index 91390dcadf0..89a35b00fa6 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll index 91390dcadf0..89a35b00fa6 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll @@ -4300,6 +4300,12 @@ private module Subpaths { ) } + pragma[nomagic] + private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) { + succ = pred.getASuccessor() and + succNode = succ.getNodeEx() + } + /** * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through * a subpath between `par` and `ret` with the connecting edges `arg -> par` and @@ -4307,15 +4313,13 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | - pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](par) and - pragma[only_bind_into](arg).getASuccessor() = out0 and + pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and + hasSuccessor(pragma[only_bind_into](arg), par, p) and not ret.isHidden() and - par.getNodeEx() = p and - out0.getNodeEx() = o and - out0.getState() = sout and - out0.getAp() = apout and - (out = out0 or out = out0.projectToSink()) + pathNode(out0, o, sout, _, _, apout, _, _) + | + out = out0 or out = out0.projectToSink() ) } From 7bcc5db4a6f52f9e2472e97415bb7b7c2e49ab56 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 5 May 2022 16:01:54 +0200 Subject: [PATCH 129/171] Swift: parametrize namespace and other things in codegen This is so that we can use this in the PoC branch. --- swift/codegen/cppgen.py | 9 ++++--- swift/codegen/lib/cpp.py | 11 ++++++-- swift/codegen/lib/options.py | 3 +++ swift/codegen/templates/cpp_classes.mustache | 14 +++++----- swift/codegen/templates/trap_tags.mustache | 2 +- swift/codegen/templates/trap_traps.mustache | 8 +++--- swift/codegen/test/test_cppgen.py | 28 ++++++++++++-------- swift/codegen/test/test_trapgen.py | 19 ++++++++++--- swift/codegen/trapgen.py | 7 +++-- swift/extractor/trap/BUILD.bazel | 14 ++++++++-- 10 files changed, 76 insertions(+), 39 deletions(-) diff --git a/swift/codegen/cppgen.py b/swift/codegen/cppgen.py index bbd65368e6f..6b2d616a348 100644 --- a/swift/codegen/cppgen.py +++ b/swift/codegen/cppgen.py @@ -1,7 +1,7 @@ import functools -import inflection from typing import Dict +import inflection from toposort import toposort_flatten from swift.codegen.lib import cpp, generator, schema @@ -20,7 +20,7 @@ def _get_type(t: str) -> str: def _get_field(cls: schema.Class, p: schema.Property) -> cpp.Field: trap_name = None if not p.is_single: - trap_name = inflection.pluralize(inflection.camelize(f"{cls.name}_{p.name}")) + "Trap" + trap_name = inflection.pluralize(inflection.camelize(f"{cls.name}_{p.name}")) args = dict( name=p.name + ("_" if p.name in cpp.cpp_keywords else ""), type=_get_type(p.type), @@ -41,7 +41,7 @@ class Processor: cls = self._classmap[name] trap_name = None if not cls.derived or any(p.is_single for p in cls.properties): - trap_name = inflection.pluralize(cls.name) + "Trap" + trap_name = inflection.pluralize(cls.name) return cpp.Class( name=name, bases=[self._get_class(b) for b in cls.bases], @@ -58,7 +58,8 @@ class Processor: def generate(opts, renderer): processor = Processor({cls.name: cls for cls in schema.load(opts.schema).classes}) out = opts.cpp_output - renderer.render(cpp.ClassList(processor.get_classes()), out / "TrapClasses.h") + renderer.render(cpp.ClassList(processor.get_classes(), opts.cpp_namespace, opts.trap_suffix, + opts.cpp_include_dir), out / "TrapClasses.h") tags = ("cpp", "schema") diff --git a/swift/codegen/lib/cpp.py b/swift/codegen/lib/cpp.py index 9395121ff5a..c3e9e25c561 100644 --- a/swift/codegen/lib/cpp.py +++ b/swift/codegen/lib/cpp.py @@ -105,14 +105,18 @@ class Tag: class TrapList: template: ClassVar = 'trap_traps' - traps: List[Trap] = field(default_factory=list) + traps: List[Trap] + namespace: str + trap_suffix: str + include_dir: str @dataclass class TagList: template: ClassVar = 'trap_tags' - tags: List[Tag] = field(default_factory=list) + tags: List[Tag] + namespace: str @dataclass @@ -148,3 +152,6 @@ class ClassList: template: ClassVar = "cpp_classes" classes: List[Class] + namespace: str + trap_suffix: str + include_dir: str diff --git a/swift/codegen/lib/options.py b/swift/codegen/lib/options.py index 9dbc19355e0..2b586a8d90b 100644 --- a/swift/codegen/lib/options.py +++ b/swift/codegen/lib/options.py @@ -16,6 +16,9 @@ def _init_options(): Option("--ql-stub-output", tags=["ql"], type=_abspath, default=paths.swift_dir / "ql/lib/codeql/swift/elements") Option("--codeql-binary", tags=["ql"], default="codeql") Option("--cpp-output", tags=["cpp"], type=_abspath, required=True) + Option("--cpp-namespace", tags=["cpp"], default="codeql") + Option("--trap-suffix", tags=["cpp"], default="Trap") + Option("--cpp-include-dir", tags=["cpp"], required=True) def _abspath(x): diff --git a/swift/codegen/templates/cpp_classes.mustache b/swift/codegen/templates/cpp_classes.mustache index 504ca92934b..33757828951 100644 --- a/swift/codegen/templates/cpp_classes.mustache +++ b/swift/codegen/templates/cpp_classes.mustache @@ -6,10 +6,10 @@ #include #include -#include "swift/extractor/trap/TrapLabel.h" -#include "swift/extractor/trap/TrapEntries.h" +#include "{{include_dir}}/TrapLabel.h" +#include "{{include_dir}}/TrapEntries.h" -namespace codeql { +namespace {{namespace}} { {{#classes}} struct {{name}}{{#final}} : Binding<{{name}}Tag>{{#bases}}, {{ref.name}}{{/bases}}{{/final}}{{^final}}{{#has_bases}}: {{#bases}}{{^first}}, {{/first}}{{ref.name}}{{/bases}}{{/has_bases}}{{/final}} { @@ -30,21 +30,21 @@ struct {{name}}{{#final}} : Binding<{{name}}Tag>{{#bases}}, {{ref.name}}{{/bases {{ref.name}}::emit(id, out); {{/bases}} {{#trap_name}} - out << {{.}}{id{{#single_fields}}, {{name}}{{/single_fields}}} << '\n'; + out << {{.}}{{trap_suffix}}{id{{#single_fields}}, {{name}}{{/single_fields}}} << '\n'; {{/trap_name}} {{#fields}} {{#is_optional}} {{^is_repeated}} - if ({{name}}) out << {{trap_name}}{id, *{{name}}} << '\n'; + if ({{name}}) out << {{trap_name}}{{trap_suffix}}{id, *{{name}}} << '\n'; {{/is_repeated}} {{/is_optional}} {{#is_repeated}} for (auto i = 0u; i < {{name}}.size(); ++i) { {{^is_optional}} - out << {{trap_name}}{id, i, {{name}}[i]}; + out << {{trap_name}}{{trap_suffix}}{id, i, {{name}}[i]}; {{/is_optional}} {{#is_optional}} - if ({{name}}[i]) out << {{trap_name}}{id, i, *{{name}}[i]}; + if ({{name}}[i]) out << {{trap_name}}{{trap_suffix}}{id, i, *{{name}}[i]}; {{/is_optional}} } {{/is_repeated}} diff --git a/swift/codegen/templates/trap_tags.mustache b/swift/codegen/templates/trap_tags.mustache index 6098bf81808..2c1631d1765 100644 --- a/swift/codegen/templates/trap_tags.mustache +++ b/swift/codegen/templates/trap_tags.mustache @@ -2,7 +2,7 @@ // clang-format off #pragma once -namespace codeql { +namespace {{namespace}} { {{#tags}} // {{id}} diff --git a/swift/codegen/templates/trap_traps.mustache b/swift/codegen/templates/trap_traps.mustache index dd1c560b958..1235c444e98 100644 --- a/swift/codegen/templates/trap_traps.mustache +++ b/swift/codegen/templates/trap_traps.mustache @@ -5,14 +5,14 @@ #include #include -#include "swift/extractor/trap/TrapLabel.h" -#include "swift/extractor/trap/TrapTags.h" +#include "{{include_dir}}/TrapLabel.h" +#include "{{include_dir}}/TrapTags.h" -namespace codeql { +namespace {{namespace}} { {{#traps}} // {{table_name}} -struct {{name}}Trap { +struct {{name}}{{trap_suffix}} { static constexpr bool is_binding = {{#id}}true{{/id}}{{^id}}false{{/id}}; {{#id}} {{type}} getBoundLabel() const { return {{cpp_name}}; } diff --git a/swift/codegen/test/test_cppgen.py b/swift/codegen/test/test_cppgen.py index 1dbb6b61bfe..c8df2b5da81 100644 --- a/swift/codegen/test/test_cppgen.py +++ b/swift/codegen/test/test_cppgen.py @@ -10,6 +10,9 @@ output_dir = pathlib.Path("path", "to", "output") @pytest.fixture def generate(opts, renderer, input): opts.cpp_output = output_dir + opts.cpp_namespace = "test_namespace" + opts.trap_suffix = "TestTrapSuffix" + opts.cpp_include_dir = "my/include/dir" def ret(classes): input.classes = classes @@ -17,6 +20,9 @@ def generate(opts, renderer, input): assert set(generated) == {output_dir / "TrapClasses.h"} generated = generated[output_dir / "TrapClasses.h"] assert isinstance(generated, cpp.ClassList) + assert generated.namespace == opts.cpp_namespace + assert generated.trap_suffix == opts.trap_suffix + assert generated.include_dir == opts.cpp_include_dir return generated.classes return ret @@ -30,7 +36,7 @@ def test_empty_class(generate): assert generate([ schema.Class(name="MyClass"), ]) == [ - cpp.Class(name="MyClass", final=True, trap_name="MyClassesTrap") + cpp.Class(name="MyClass", final=True, trap_name="MyClasses") ] @@ -41,7 +47,7 @@ def test_two_class_hierarchy(generate): schema.Class(name="B", bases={"A"}), ]) == [ base, - cpp.Class(name="B", bases=[base], final=True, trap_name="BsTrap"), + cpp.Class(name="B", bases=[base], final=True, trap_name="Bs"), ] @@ -50,8 +56,8 @@ def test_complex_hierarchy_topologically_ordered(generate): b = cpp.Class(name="B") c = cpp.Class(name="C", bases=[a]) d = cpp.Class(name="D", bases=[a]) - e = cpp.Class(name="E", bases=[b, c, d], final=True, trap_name="EsTrap") - f = cpp.Class(name="F", bases=[c], final=True, trap_name="FsTrap") + e = cpp.Class(name="E", bases=[b, c, d], final=True, trap_name="Es") + f = cpp.Class(name="F", bases=[c], final=True, trap_name="Fs") assert generate([ schema.Class(name="F", bases={"C"}), schema.Class(name="B", derived={"E"}), @@ -70,9 +76,9 @@ def test_complex_hierarchy_topologically_ordered(generate): ]) @pytest.mark.parametrize("property_cls,optional,repeated,trap_name", [ (schema.SingleProperty, False, False, None), - (schema.OptionalProperty, True, False, "MyClassPropsTrap"), - (schema.RepeatedProperty, False, True, "MyClassPropsTrap"), - (schema.RepeatedOptionalProperty, True, True, "MyClassPropsTrap"), + (schema.OptionalProperty, True, False, "MyClassProps"), + (schema.RepeatedProperty, False, True, "MyClassProps"), + (schema.RepeatedOptionalProperty, True, True, "MyClassProps"), ]) def test_class_with_field(generate, type, expected, property_cls, optional, repeated, trap_name): assert generate([ @@ -81,7 +87,7 @@ def test_class_with_field(generate, type, expected, property_cls, optional, repe cpp.Class(name="MyClass", fields=[cpp.Field("prop", expected, is_optional=optional, is_repeated=repeated, trap_name=trap_name)], - trap_name="MyClassesTrap", + trap_name="MyClasses", final=True) ] @@ -94,7 +100,7 @@ def test_class_with_overridden_unsigned_field(generate, name): ]) == [ cpp.Class(name="MyClass", fields=[cpp.Field(name, "unsigned")], - trap_name="MyClassesTrap", + trap_name="MyClasses", final=True) ] @@ -106,7 +112,7 @@ def test_class_with_overridden_underscore_field(generate): ]) == [ cpp.Class(name="MyClass", fields=[cpp.Field("something", "bar")], - trap_name="MyClassesTrap", + trap_name="MyClasses", final=True) ] @@ -119,7 +125,7 @@ def test_class_with_keyword_field(generate, name): ]) == [ cpp.Class(name="MyClass", fields=[cpp.Field(name + "_", "bar")], - trap_name="MyClassesTrap", + trap_name="MyClasses", final=True) ] diff --git a/swift/codegen/test/test_trapgen.py b/swift/codegen/test/test_trapgen.py index 5ac6cd3718c..37fb5b062e1 100644 --- a/swift/codegen/test/test_trapgen.py +++ b/swift/codegen/test/test_trapgen.py @@ -10,6 +10,9 @@ output_dir = pathlib.Path("path", "to", "output") @pytest.fixture def generate(opts, renderer, dbscheme_input): opts.cpp_output = output_dir + opts.cpp_namespace = "test_namespace" + opts.trap_suffix = "TrapSuffix" + opts.cpp_include_dir = "my/include/dir" def ret(entities): dbscheme_input.entities = entities @@ -22,27 +25,35 @@ def generate(opts, renderer, dbscheme_input): @pytest.fixture -def generate_traps(generate): +def generate_traps(opts, generate): def ret(entities): traps, _ = generate(entities) assert isinstance(traps, cpp.TrapList) + assert traps.namespace == opts.cpp_namespace + assert traps.trap_suffix == opts.trap_suffix + assert traps.include_dir == opts.cpp_include_dir return traps.traps return ret @pytest.fixture -def generate_tags(generate): +def generate_tags(opts, generate): def ret(entities): _, tags = generate(entities) assert isinstance(tags, cpp.TagList) + assert tags.namespace == opts.cpp_namespace return tags.tags return ret -def test_empty(generate): - assert generate([]) == (cpp.TrapList([]), cpp.TagList([])) +def test_empty_traps(generate_traps): + assert generate_traps([]) == [] + + +def test_empty_tags(generate_tags): + assert generate_tags([]) == [] def test_one_empty_table_rejected(generate_traps): diff --git a/swift/codegen/trapgen.py b/swift/codegen/trapgen.py index 555b5bf9fdb..797ce5ed215 100755 --- a/swift/codegen/trapgen.py +++ b/swift/codegen/trapgen.py @@ -1,14 +1,12 @@ #!/usr/bin/env python3 import logging -import re import inflection from toposort import toposort_flatten from swift.codegen.lib import dbscheme, generator, cpp - log = logging.getLogger(__name__) @@ -70,7 +68,8 @@ def generate(opts, renderer): for d in e.rhs: tag_graph.setdefault(d.type, set()).add(e.lhs) - renderer.render(cpp.TrapList(traps), out / "TrapEntries.h") + renderer.render(cpp.TrapList(traps, opts.cpp_namespace, opts.trap_suffix, opts.cpp_include_dir), + out / "TrapEntries.h") tags = [] for index, tag in enumerate(toposort_flatten(tag_graph)): @@ -80,7 +79,7 @@ def generate(opts, renderer): index=index, id=tag, )) - renderer.render(cpp.TagList(tags), out / "TrapTags.h") + renderer.render(cpp.TagList(tags, opts.cpp_namespace), out / "TrapTags.h") tags = ("cpp", "dbscheme") diff --git a/swift/extractor/trap/BUILD.bazel b/swift/extractor/trap/BUILD.bazel index 7fa90c89e91..be611f3ddc6 100644 --- a/swift/extractor/trap/BUILD.bazel +++ b/swift/extractor/trap/BUILD.bazel @@ -5,7 +5,12 @@ genrule( "TrapEntries.h", "TrapTags.h", ], - cmd = "$(location //swift/codegen:trapgen) --dbscheme $< --cpp-output $(RULEDIR)", + cmd = " ".join([ + "$(location //swift/codegen:trapgen)", + "--dbscheme $<", + "--cpp-include-dir " + package_name(), + "--cpp-output $(RULEDIR)", + ]), exec_tools = ["//swift/codegen:trapgen"], ) @@ -18,7 +23,12 @@ genrule( outs = [ "TrapClasses.h", ], - cmd = "$(location //swift/codegen:cppgen) --schema $(location //swift/codegen:schema) --cpp-output $(RULEDIR)", + cmd = " ".join([ + "$(location //swift/codegen:cppgen)", + "--schema $(location //swift/codegen:schema)", + "--cpp-include-dir " + package_name(), + "--cpp-output $(RULEDIR)", + ]), exec_tools = ["//swift/codegen:cppgen"], ) From ac3cceab19c843ba30a9133c65bc4e7e63fa894d Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 5 May 2022 16:15:16 +0200 Subject: [PATCH 130/171] Swift: turn some generated paths to relative --- swift/codegen/templates/cpp_classes.mustache | 2 +- swift/codegen/templates/trap_traps.mustache | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/codegen/templates/cpp_classes.mustache b/swift/codegen/templates/cpp_classes.mustache index 33757828951..7fedf77884a 100644 --- a/swift/codegen/templates/cpp_classes.mustache +++ b/swift/codegen/templates/cpp_classes.mustache @@ -7,7 +7,7 @@ #include #include "{{include_dir}}/TrapLabel.h" -#include "{{include_dir}}/TrapEntries.h" +#include "./TrapEntries.h" namespace {{namespace}} { {{#classes}} diff --git a/swift/codegen/templates/trap_traps.mustache b/swift/codegen/templates/trap_traps.mustache index 1235c444e98..6cc0f6299a7 100644 --- a/swift/codegen/templates/trap_traps.mustache +++ b/swift/codegen/templates/trap_traps.mustache @@ -6,7 +6,7 @@ #include #include "{{include_dir}}/TrapLabel.h" -#include "{{include_dir}}/TrapTags.h" +#include "./TrapTags.h" namespace {{namespace}} { {{#traps}} From c4bc7050a9ae60e2c10917ec625de4a18e6c4380 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 5 May 2022 16:26:09 +0100 Subject: [PATCH 131/171] C++: Additional test cases. --- .../query-tests/Security/CWE/CWE-611/tests.h | 1 + .../Security/CWE/CWE-611/tests3.cpp | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests.h b/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests.h index 65baa12ed9e..7d745382174 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests.h +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests.h @@ -21,5 +21,6 @@ class XMLUni { public: static const XMLCh fgXercesDisableDefaultEntityResolution[]; + static const XMLCh fgXercesHarmlessOption[]; }; diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests3.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests3.cpp index 96f8dbaef06..622ed016200 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests3.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests3.cpp @@ -55,3 +55,28 @@ void test3_5(InputSource &data) { test3_5_init(); p_3_5->parse(data); // GOOD } + +void test3_6(InputSource &data) { + SAX2XMLReader *p = XMLReaderFactory::createXMLReader(); + + p->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, false); + p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED] +} + +void test3_7(InputSource &data) { + SAX2XMLReader *p = XMLReaderFactory::createXMLReader(); + + p->setFeature(XMLUni::fgXercesHarmlessOption, true); + p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED] +} + +void test3_8(InputSource &data) { + SAX2XMLReader *p = XMLReaderFactory::createXMLReader(); + const XMLCh *feature = XMLUni::fgXercesDisableDefaultEntityResolution; + + p->setFeature(feature, true); + p->parse(data); // GOOD +} + + + From b2b5fd281ff183321f5e126e28f67deb6f13a905 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 5 May 2022 17:34:00 +0200 Subject: [PATCH 132/171] Swift: add more parametrization This enables codegen to run on the swift PoC branch. --- swift/codegen/cppgen.py | 19 +++++++++-------- swift/codegen/dbschemegen.py | 8 +++---- swift/codegen/lib/cpp.py | 4 ++-- swift/codegen/lib/options.py | 3 ++- swift/codegen/qlgen.py | 9 ++++---- swift/codegen/templates/cpp_classes.mustache | 12 +++++------ swift/codegen/templates/trap_traps.mustache | 8 +++---- swift/codegen/test/test_cppgen.py | 10 ++++----- swift/codegen/test/test_trapgen.py | 10 ++++----- swift/codegen/test/utils.py | 6 ++++-- swift/codegen/trapgen.py | 22 ++++++++++---------- 11 files changed, 58 insertions(+), 53 deletions(-) diff --git a/swift/codegen/cppgen.py b/swift/codegen/cppgen.py index 6b2d616a348..f45512512aa 100644 --- a/swift/codegen/cppgen.py +++ b/swift/codegen/cppgen.py @@ -7,23 +7,23 @@ from toposort import toposort_flatten from swift.codegen.lib import cpp, generator, schema -def _get_type(t: str) -> str: +def _get_type(t: str, trap_affix: str) -> str: if t == "string": return "std::string" if t == "boolean": return "bool" if t[0].isupper(): - return f"TrapLabel<{t}Tag>" + return f"{trap_affix}Label<{t}Tag>" return t -def _get_field(cls: schema.Class, p: schema.Property) -> cpp.Field: +def _get_field(cls: schema.Class, p: schema.Property, trap_affix: str) -> cpp.Field: trap_name = None if not p.is_single: trap_name = inflection.pluralize(inflection.camelize(f"{cls.name}_{p.name}")) args = dict( name=p.name + ("_" if p.name in cpp.cpp_keywords else ""), - type=_get_type(p.type), + type=_get_type(p.type, trap_affix), is_optional=p.is_optional, is_repeated=p.is_repeated, trap_name=trap_name, @@ -33,8 +33,9 @@ def _get_field(cls: schema.Class, p: schema.Property) -> cpp.Field: class Processor: - def __init__(self, data: Dict[str, schema.Class]): + def __init__(self, data: Dict[str, schema.Class], trap_affix: str): self._classmap = data + self._trap_affix = trap_affix @functools.lru_cache(maxsize=None) def _get_class(self, name: str) -> cpp.Class: @@ -45,7 +46,7 @@ class Processor: return cpp.Class( name=name, bases=[self._get_class(b) for b in cls.bases], - fields=[_get_field(cls, p) for p in cls.properties], + fields=[_get_field(cls, p, self._trap_affix) for p in cls.properties], final=not cls.derived, trap_name=trap_name, ) @@ -56,10 +57,10 @@ class Processor: def generate(opts, renderer): - processor = Processor({cls.name: cls for cls in schema.load(opts.schema).classes}) + processor = Processor({cls.name: cls for cls in schema.load(opts.schema).classes}, opts.trap_affix) out = opts.cpp_output - renderer.render(cpp.ClassList(processor.get_classes(), opts.cpp_namespace, opts.trap_suffix, - opts.cpp_include_dir), out / "TrapClasses.h") + renderer.render(cpp.ClassList(processor.get_classes(), opts.cpp_namespace, opts.trap_affix, + opts.cpp_include_dir), out / f"{opts.trap_affix}Classes.h") tags = ("cpp", "schema") diff --git a/swift/codegen/dbschemegen.py b/swift/codegen/dbschemegen.py index c99cec1ea29..efe45c0b997 100755 --- a/swift/codegen/dbschemegen.py +++ b/swift/codegen/dbschemegen.py @@ -63,12 +63,12 @@ def get_declarations(data: schema.Schema): return [d for cls in data.classes for d in cls_to_dbscheme(cls)] -def get_includes(data: schema.Schema, include_dir: pathlib.Path): +def get_includes(data: schema.Schema, include_dir: pathlib.Path, swift_dir: pathlib.Path): includes = [] for inc in data.includes: inc = include_dir / inc with open(inc) as inclusion: - includes.append(SchemeInclude(src=inc.relative_to(paths.swift_dir), data=inclusion.read())) + includes.append(SchemeInclude(src=inc.relative_to(swift_dir), data=inclusion.read())) return includes @@ -78,8 +78,8 @@ def generate(opts, renderer): data = schema.load(input) - dbscheme = Scheme(src=input.relative_to(paths.swift_dir), - includes=get_includes(data, include_dir=input.parent), + dbscheme = Scheme(src=input.relative_to(opts.swift_dir), + includes=get_includes(data, include_dir=input.parent, swift_dir=opts.swift_dir), declarations=get_declarations(data)) renderer.render(dbscheme, out) diff --git a/swift/codegen/lib/cpp.py b/swift/codegen/lib/cpp.py index c3e9e25c561..7e360fcddf6 100644 --- a/swift/codegen/lib/cpp.py +++ b/swift/codegen/lib/cpp.py @@ -107,7 +107,7 @@ class TrapList: traps: List[Trap] namespace: str - trap_suffix: str + trap_affix: str include_dir: str @@ -153,5 +153,5 @@ class ClassList: classes: List[Class] namespace: str - trap_suffix: str + trap_affix: str include_dir: str diff --git a/swift/codegen/lib/options.py b/swift/codegen/lib/options.py index 2b586a8d90b..52de34d864e 100644 --- a/swift/codegen/lib/options.py +++ b/swift/codegen/lib/options.py @@ -10,6 +10,7 @@ from . import paths def _init_options(): Option("--verbose", "-v", action="store_true") + Option("--swift-dir", type=_abspath, default=paths.swift_dir) Option("--schema", tags=["schema"], type=_abspath, default=paths.swift_dir / "codegen/schema.yml") Option("--dbscheme", tags=["dbscheme"], type=_abspath, default=paths.swift_dir / "ql/lib/swift.dbscheme") Option("--ql-output", tags=["ql"], type=_abspath, default=paths.swift_dir / "ql/lib/codeql/swift/generated") @@ -17,7 +18,7 @@ def _init_options(): Option("--codeql-binary", tags=["ql"], default="codeql") Option("--cpp-output", tags=["cpp"], type=_abspath, required=True) Option("--cpp-namespace", tags=["cpp"], default="codeql") - Option("--trap-suffix", tags=["cpp"], default="Trap") + Option("--trap-affix", tags=["cpp"], default="Trap") Option("--cpp-include-dir", tags=["cpp"], required=True) diff --git a/swift/codegen/qlgen.py b/swift/codegen/qlgen.py index 26a5e2edcae..ad44a234c77 100755 --- a/swift/codegen/qlgen.py +++ b/swift/codegen/qlgen.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import logging +import pathlib import subprocess import inflection @@ -47,8 +48,8 @@ def get_ql_class(cls: schema.Class): ) -def get_import(file): - stem = file.relative_to(paths.swift_dir / "ql/lib").with_suffix("") +def get_import(file: pathlib.Path, swift_dir: pathlib.Path): + stem = file.relative_to(swift_dir / "ql/lib").with_suffix("") return str(stem).replace("/", ".") @@ -89,7 +90,7 @@ def generate(opts, renderer): imports = {} for c in classes: - imports[c.name] = get_import(stub_out / c.path) + imports[c.name] = get_import(stub_out / c.path, opts.swift_dir) for c in classes: qll = (out / c.path).with_suffix(".qll") @@ -97,7 +98,7 @@ def generate(opts, renderer): renderer.render(c, qll) stub_file = (stub_out / c.path).with_suffix(".qll") if not stub_file.is_file() or is_generated(stub_file): - stub = ql.Stub(name=c.name, base_import=get_import(qll)) + stub = ql.Stub(name=c.name, base_import=get_import(qll, opts.swift_dir)) renderer.render(stub, stub_file) # for example path/to/syntax/generated -> path/to/syntax.qll diff --git a/swift/codegen/templates/cpp_classes.mustache b/swift/codegen/templates/cpp_classes.mustache index 7fedf77884a..4dddf4dab06 100644 --- a/swift/codegen/templates/cpp_classes.mustache +++ b/swift/codegen/templates/cpp_classes.mustache @@ -6,8 +6,8 @@ #include #include -#include "{{include_dir}}/TrapLabel.h" -#include "./TrapEntries.h" +#include "{{include_dir}}/{{trap_affix}}Label.h" +#include "./{{trap_affix}}Entries.h" namespace {{namespace}} { {{#classes}} @@ -30,21 +30,21 @@ struct {{name}}{{#final}} : Binding<{{name}}Tag>{{#bases}}, {{ref.name}}{{/bases {{ref.name}}::emit(id, out); {{/bases}} {{#trap_name}} - out << {{.}}{{trap_suffix}}{id{{#single_fields}}, {{name}}{{/single_fields}}} << '\n'; + out << {{.}}{{trap_affix}}{id{{#single_fields}}, {{name}}{{/single_fields}}} << '\n'; {{/trap_name}} {{#fields}} {{#is_optional}} {{^is_repeated}} - if ({{name}}) out << {{trap_name}}{{trap_suffix}}{id, *{{name}}} << '\n'; + if ({{name}}) out << {{trap_name}}{{trap_affix}}{id, *{{name}}} << '\n'; {{/is_repeated}} {{/is_optional}} {{#is_repeated}} for (auto i = 0u; i < {{name}}.size(); ++i) { {{^is_optional}} - out << {{trap_name}}{{trap_suffix}}{id, i, {{name}}[i]}; + out << {{trap_name}}{{trap_affix}}{id, i, {{name}}[i]}; {{/is_optional}} {{#is_optional}} - if ({{name}}[i]) out << {{trap_name}}{{trap_suffix}}{id, i, *{{name}}[i]}; + if ({{name}}[i]) out << {{trap_name}}{{trap_affix}}{id, i, *{{name}}[i]}; {{/is_optional}} } {{/is_repeated}} diff --git a/swift/codegen/templates/trap_traps.mustache b/swift/codegen/templates/trap_traps.mustache index 6cc0f6299a7..1848d3fbc87 100644 --- a/swift/codegen/templates/trap_traps.mustache +++ b/swift/codegen/templates/trap_traps.mustache @@ -5,14 +5,14 @@ #include #include -#include "{{include_dir}}/TrapLabel.h" -#include "./TrapTags.h" +#include "{{include_dir}}/{{trap_affix}}Label.h" +#include "./{{trap_affix}}Tags.h" namespace {{namespace}} { {{#traps}} // {{table_name}} -struct {{name}}{{trap_suffix}} { +struct {{name}}{{trap_affix}} { static constexpr bool is_binding = {{#id}}true{{/id}}{{^id}}false{{/id}}; {{#id}} {{type}} getBoundLabel() const { return {{cpp_name}}; } @@ -23,7 +23,7 @@ struct {{name}}{{trap_suffix}} { {{/fields}} }; -inline std::ostream &operator<<(std::ostream &out, const {{name}}Trap &e) { +inline std::ostream &operator<<(std::ostream &out, const {{name}}{{trap_affix}} &e) { out << "{{table_name}}("{{#fields}}{{^first}} << ", "{{/first}} << {{#get_streamer}}e.{{cpp_name}}{{/get_streamer}}{{/fields}} << ")"; return out; diff --git a/swift/codegen/test/test_cppgen.py b/swift/codegen/test/test_cppgen.py index c8df2b5da81..b47a1159df1 100644 --- a/swift/codegen/test/test_cppgen.py +++ b/swift/codegen/test/test_cppgen.py @@ -11,17 +11,17 @@ output_dir = pathlib.Path("path", "to", "output") def generate(opts, renderer, input): opts.cpp_output = output_dir opts.cpp_namespace = "test_namespace" - opts.trap_suffix = "TestTrapSuffix" + opts.trap_affix = "TestTrapAffix" opts.cpp_include_dir = "my/include/dir" def ret(classes): input.classes = classes generated = run_generation(cppgen.generate, opts, renderer) - assert set(generated) == {output_dir / "TrapClasses.h"} - generated = generated[output_dir / "TrapClasses.h"] + assert set(generated) == {output_dir / "TestTrapAffixClasses.h"} + generated = generated[output_dir / "TestTrapAffixClasses.h"] assert isinstance(generated, cpp.ClassList) assert generated.namespace == opts.cpp_namespace - assert generated.trap_suffix == opts.trap_suffix + assert generated.trap_affix == opts.trap_affix assert generated.include_dir == opts.cpp_include_dir return generated.classes @@ -72,7 +72,7 @@ def test_complex_hierarchy_topologically_ordered(generate): ("a", "a"), ("string", "std::string"), ("boolean", "bool"), - ("MyClass", "TrapLabel"), + ("MyClass", "TestTrapAffixLabel"), ]) @pytest.mark.parametrize("property_cls,optional,repeated,trap_name", [ (schema.SingleProperty, False, False, None), diff --git a/swift/codegen/test/test_trapgen.py b/swift/codegen/test/test_trapgen.py index 37fb5b062e1..2aad0da1203 100644 --- a/swift/codegen/test/test_trapgen.py +++ b/swift/codegen/test/test_trapgen.py @@ -11,15 +11,15 @@ output_dir = pathlib.Path("path", "to", "output") def generate(opts, renderer, dbscheme_input): opts.cpp_output = output_dir opts.cpp_namespace = "test_namespace" - opts.trap_suffix = "TrapSuffix" + opts.trap_affix = "TrapAffix" opts.cpp_include_dir = "my/include/dir" def ret(entities): dbscheme_input.entities = entities generated = run_generation(trapgen.generate, opts, renderer) assert set(generated) == {output_dir / - "TrapEntries.h", output_dir / "TrapTags.h"} - return generated[output_dir / "TrapEntries.h"], generated[output_dir / "TrapTags.h"] + "TrapAffixEntries.h", output_dir / "TrapAffixTags.h"} + return generated[output_dir / "TrapAffixEntries.h"], generated[output_dir / "TrapAffixTags.h"] return ret @@ -30,7 +30,7 @@ def generate_traps(opts, generate): traps, _ = generate(entities) assert isinstance(traps, cpp.TrapList) assert traps.namespace == opts.cpp_namespace - assert traps.trap_suffix == opts.trap_suffix + assert traps.trap_affix == opts.trap_affix assert traps.include_dir == opts.cpp_include_dir return traps.traps @@ -106,7 +106,7 @@ def test_one_table_with_two_binding_first_is_id(generate_traps): @pytest.mark.parametrize("column,field", [ (dbscheme.Column("x", "string"), cpp.Field("x", "std::string")), (dbscheme.Column("y", "boolean"), cpp.Field("y", "bool")), - (dbscheme.Column("z", "@db_type"), cpp.Field("z", "TrapLabel")), + (dbscheme.Column("z", "@db_type"), cpp.Field("z", "TrapAffixLabel")), ]) def test_one_table_special_types(generate_traps, column, field): assert generate_traps([ diff --git a/swift/codegen/test/utils.py b/swift/codegen/test/utils.py index 038caf01571..bf646297af5 100644 --- a/swift/codegen/test/utils.py +++ b/swift/codegen/test/utils.py @@ -3,7 +3,7 @@ from unittest import mock import pytest -from swift.codegen.lib import render, schema +from swift.codegen.lib import render, schema, paths schema_dir = pathlib.Path("a", "dir") schema_file = schema_dir / "schema.yml" @@ -23,7 +23,9 @@ def renderer(): @pytest.fixture def opts(): - return mock.MagicMock() + ret = mock.MagicMock() + ret.swift_dir = paths.swift_dir + return ret @pytest.fixture(autouse=True) diff --git a/swift/codegen/trapgen.py b/swift/codegen/trapgen.py index 797ce5ed215..495a51a8388 100755 --- a/swift/codegen/trapgen.py +++ b/swift/codegen/trapgen.py @@ -15,10 +15,10 @@ def get_tag_name(s): return inflection.camelize(s[1:]) -def get_cpp_type(schema_type): +def get_cpp_type(schema_type: str, trap_affix: str): if schema_type.startswith("@"): tag = get_tag_name(schema_type) - return f"TrapLabel<{tag}Tag>" + return f"{trap_affix}Label<{tag}Tag>" if schema_type == "string": return "std::string" if schema_type == "boolean": @@ -26,13 +26,13 @@ def get_cpp_type(schema_type): return schema_type -def get_field(c: dbscheme.Column, table: str): +def get_field(c: dbscheme.Column, trap_affix: str): args = { "name": c.schema_name, "type": c.type, } args.update(cpp.get_field_override(c.schema_name)) - args["type"] = get_cpp_type(args["type"]) + args["type"] = get_cpp_type(args["type"], trap_affix) return cpp.Field(**args) @@ -43,14 +43,14 @@ def get_binding_column(t: dbscheme.Table): return None -def get_trap(t: dbscheme.Table): +def get_trap(t: dbscheme.Table, trap_affix: str): id = get_binding_column(t) if id: - id = get_field(id, t.name) + id = get_field(id, trap_affix) return cpp.Trap( table_name=t.name, name=inflection.camelize(t.name), - fields=[get_field(c, t.name) for c in t.columns], + fields=[get_field(c, trap_affix) for c in t.columns], id=id, ) @@ -62,14 +62,14 @@ def generate(opts, renderer): traps = [] for e in dbscheme.iterload(opts.dbscheme): if e.is_table: - traps.append(get_trap(e)) + traps.append(get_trap(e, opts.trap_affix)) elif e.is_union: tag_graph.setdefault(e.lhs, set()) for d in e.rhs: tag_graph.setdefault(d.type, set()).add(e.lhs) - renderer.render(cpp.TrapList(traps, opts.cpp_namespace, opts.trap_suffix, opts.cpp_include_dir), - out / "TrapEntries.h") + renderer.render(cpp.TrapList(traps, opts.cpp_namespace, opts.trap_affix, opts.cpp_include_dir), + out / f"{opts.trap_affix}Entries.h") tags = [] for index, tag in enumerate(toposort_flatten(tag_graph)): @@ -79,7 +79,7 @@ def generate(opts, renderer): index=index, id=tag, )) - renderer.render(cpp.TagList(tags, opts.cpp_namespace), out / "TrapTags.h") + renderer.render(cpp.TagList(tags, opts.cpp_namespace), out / f"{opts.trap_affix}Tags.h") tags = ("cpp", "dbscheme") From 6b5a1921dd32e6fe0c5f0119532d238676ca28e1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 3 May 2022 17:56:27 +0100 Subject: [PATCH 133/171] C++: Support the SAX2XMLReader interface. --- cpp/ql/src/Security/CWE/CWE-611/XXE.ql | 74 ++++++++++++++++++- .../Security/CWE/CWE-611/XXE.expected | 12 +++ .../Security/CWE/CWE-611/tests3.cpp | 4 +- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql index 43b4d0c0c01..349e576862f 100644 --- a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql +++ b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql @@ -64,6 +64,13 @@ class SAXParserClass extends Class { SAXParserClass() { this.hasName("SAXParser") } } +/** + * The `SAX2XMLReader` class. + */ +class SAX2XMLReader extends Class { + SAX2XMLReader() { this.hasName("SAX2XMLReader") } +} + /** * Gets a valid flow state for `AbstractDOMParser` or `SAXParser` flow. * @@ -168,12 +175,57 @@ class CreateEntityReferenceNodesTranformer extends XXEFlowStateTranformer { } /** - * The `AbstractDOMParser.parse` or `SAXParser.parse` method. + * The `XMLUni.fgXercesDisableDefaultEntityResolution` constant. + */ +class FeatureDisableDefaultEntityResolution extends Variable { + FeatureDisableDefaultEntityResolution() { + this.getName() = "fgXercesDisableDefaultEntityResolution" and + this.getDeclaringType().getName() = "XMLUni" + } +} + +/** + * A flow state transformer for a call to `SAX2XMLReader.setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, *)`. Transforms the flow + * state through the qualifier according to this setting. + */ +class SetFeatureTranformer extends XXEFlowStateTranformer { + Expr newValue; + + SetFeatureTranformer() { + exists(Call call, Function f | + call.getTarget() = f and + f.getDeclaringType() instanceof SAX2XMLReader and + f.hasName("setFeature") and + this = call.getQualifier() and + globalValueNumber(call.getArgument(0)).getAnExpr().(VariableAccess).getTarget() instanceof + FeatureDisableDefaultEntityResolution and + newValue = call.getArgument(1) + ) + } + + final override XXEFlowState transform(XXEFlowState flowstate) { + exists(int createEntityReferenceNodes | + encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and + ( + globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true + encodeXercesFlowState(result, 1, createEntityReferenceNodes) + or + not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown + encodeXercesFlowState(result, 0, createEntityReferenceNodes) + ) + ) + } +} + +/** + * The `AbstractDOMParser.parse`, `SAXParser.parse` or `SAX2XMLReader.parse` + * method. */ class ParseFunction extends Function { ParseFunction() { this.getClassAndName("parse") instanceof AbstractDOMParserClass or - this.getClassAndName("parse") instanceof SAXParserClass + this.getClassAndName("parse") instanceof SAXParserClass or + this.getClassAndName("parse") instanceof SAX2XMLReader } } @@ -188,6 +240,17 @@ class CreateLSParser extends Function { } } +/** + * The `createXMLReader` function that returns a newly created `SAX2XMLReader` + * object. + */ +class CreateXMLReader extends Function { + CreateXMLReader() { + this.hasName("createXMLReader") and + this.getUnspecifiedType().(PointerType).getBaseType() instanceof SAX2XMLReader // returns a `SAX2XMLReader *`. + } +} + /** * A call to a `libxml2` function that parses XML. */ @@ -256,6 +319,13 @@ class XXEConfiguration extends DataFlow::Configuration { encodeXercesFlowState(flowstate, 0, 1) // default configuration ) or + // source is the result of a call to `createXMLReader`. + exists(Call call | + call.getTarget() instanceof CreateXMLReader and + call = node.asExpr() and + encodeXercesFlowState(flowstate, 0, 1) // default configuration + ) + or // source is an `options` argument on a `libxml2` parse call that specifies // at least one unsafe option. // diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-611/XXE.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-611/XXE.expected index 9e005341b9a..24371939674 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-611/XXE.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-611/XXE.expected @@ -1,6 +1,9 @@ edges | tests2.cpp:20:17:20:31 | SAXParser output argument | tests2.cpp:22:2:22:2 | p | | tests2.cpp:33:17:33:31 | SAXParser output argument | tests2.cpp:37:2:37:2 | p | +| tests3.cpp:23:21:23:53 | call to createXMLReader | tests3.cpp:25:2:25:2 | p | +| tests3.cpp:60:21:60:53 | call to createXMLReader | tests3.cpp:63:2:63:2 | p | +| tests3.cpp:67:21:67:53 | call to createXMLReader | tests3.cpp:70:2:70:2 | p | | tests.cpp:15:23:15:43 | XercesDOMParser output argument | tests.cpp:17:2:17:2 | p | | tests.cpp:28:23:28:43 | XercesDOMParser output argument | tests.cpp:31:2:31:2 | p | | tests.cpp:35:19:35:19 | VariableAddress [post update] | tests.cpp:37:2:37:2 | p | @@ -32,6 +35,12 @@ nodes | tests2.cpp:22:2:22:2 | p | semmle.label | p | | tests2.cpp:33:17:33:31 | SAXParser output argument | semmle.label | SAXParser output argument | | tests2.cpp:37:2:37:2 | p | semmle.label | p | +| tests3.cpp:23:21:23:53 | call to createXMLReader | semmle.label | call to createXMLReader | +| tests3.cpp:25:2:25:2 | p | semmle.label | p | +| tests3.cpp:60:21:60:53 | call to createXMLReader | semmle.label | call to createXMLReader | +| tests3.cpp:63:2:63:2 | p | semmle.label | p | +| tests3.cpp:67:21:67:53 | call to createXMLReader | semmle.label | call to createXMLReader | +| tests3.cpp:70:2:70:2 | p | semmle.label | p | | tests4.cpp:26:34:26:48 | (int)... | semmle.label | (int)... | | tests4.cpp:36:34:36:50 | (int)... | semmle.label | (int)... | | tests4.cpp:46:34:46:68 | ... \| ... | semmle.label | ... \| ... | @@ -76,6 +85,9 @@ subpaths #select | tests2.cpp:22:2:22:2 | p | tests2.cpp:20:17:20:31 | SAXParser output argument | tests2.cpp:22:2:22:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests2.cpp:20:17:20:31 | SAXParser output argument | XML parser | | tests2.cpp:37:2:37:2 | p | tests2.cpp:33:17:33:31 | SAXParser output argument | tests2.cpp:37:2:37:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests2.cpp:33:17:33:31 | SAXParser output argument | XML parser | +| tests3.cpp:25:2:25:2 | p | tests3.cpp:23:21:23:53 | call to createXMLReader | tests3.cpp:25:2:25:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests3.cpp:23:21:23:53 | call to createXMLReader | XML parser | +| tests3.cpp:63:2:63:2 | p | tests3.cpp:60:21:60:53 | call to createXMLReader | tests3.cpp:63:2:63:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests3.cpp:60:21:60:53 | call to createXMLReader | XML parser | +| tests3.cpp:70:2:70:2 | p | tests3.cpp:67:21:67:53 | call to createXMLReader | tests3.cpp:70:2:70:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests3.cpp:67:21:67:53 | call to createXMLReader | XML parser | | tests4.cpp:26:34:26:48 | (int)... | tests4.cpp:26:34:26:48 | (int)... | tests4.cpp:26:34:26:48 | (int)... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:26:34:26:48 | (int)... | XML parser | | tests4.cpp:36:34:36:50 | (int)... | tests4.cpp:36:34:36:50 | (int)... | tests4.cpp:36:34:36:50 | (int)... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:36:34:36:50 | (int)... | XML parser | | tests4.cpp:46:34:46:68 | ... \| ... | tests4.cpp:46:34:46:68 | ... \| ... | tests4.cpp:46:34:46:68 | ... \| ... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:46:34:46:68 | ... \| ... | XML parser | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests3.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests3.cpp index 622ed016200..15e518daf13 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests3.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-611/tests3.cpp @@ -60,14 +60,14 @@ void test3_6(InputSource &data) { SAX2XMLReader *p = XMLReaderFactory::createXMLReader(); p->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, false); - p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED] + p->parse(data); // BAD (parser not correctly configured) } void test3_7(InputSource &data) { SAX2XMLReader *p = XMLReaderFactory::createXMLReader(); p->setFeature(XMLUni::fgXercesHarmlessOption, true); - p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED] + p->parse(data); // BAD (parser not correctly configured) } void test3_8(InputSource &data) { From 453dadea1a58e89249e9384c412e05d022806ea3 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 5 May 2022 16:42:09 +0100 Subject: [PATCH 134/171] C++: Fix QLDoc. --- cpp/ql/src/Security/CWE/CWE-611/XXE.ql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql index 349e576862f..413bcfa04f1 100644 --- a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql +++ b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql @@ -185,8 +185,9 @@ class FeatureDisableDefaultEntityResolution extends Variable { } /** - * A flow state transformer for a call to `SAX2XMLReader.setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, *)`. Transforms the flow - * state through the qualifier according to this setting. + * A flow state transformer for a call to `SAX2XMLReader.setFeature` + * specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`. + * Transforms the flow state through the qualifier according to this setting. */ class SetFeatureTranformer extends XXEFlowStateTranformer { Expr newValue; From a7129c1f4c420e8575e128b1e41b6ddc2a9ba699 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 5 May 2022 18:33:05 +0200 Subject: [PATCH 135/171] Swift: add `--ql-format`/`--no-ql-format` to `codegen` --- swift/codegen/lib/options.py | 2 ++ swift/codegen/qlgen.py | 3 ++- swift/codegen/test/test_qlgen.py | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/swift/codegen/lib/options.py b/swift/codegen/lib/options.py index 52de34d864e..13f173d8dbd 100644 --- a/swift/codegen/lib/options.py +++ b/swift/codegen/lib/options.py @@ -15,6 +15,8 @@ def _init_options(): Option("--dbscheme", tags=["dbscheme"], type=_abspath, default=paths.swift_dir / "ql/lib/swift.dbscheme") Option("--ql-output", tags=["ql"], type=_abspath, default=paths.swift_dir / "ql/lib/codeql/swift/generated") Option("--ql-stub-output", tags=["ql"], type=_abspath, default=paths.swift_dir / "ql/lib/codeql/swift/elements") + Option("--ql-format", tags=["ql"], action="store_true", default=True) + Option("--no-ql-format", tags=["ql"], action="store_false", dest="ql_format") Option("--codeql-binary", tags=["ql"], default="codeql") Option("--cpp-output", tags=["cpp"], type=_abspath, required=True) Option("--cpp-namespace", tags=["cpp"], default="codeql") diff --git a/swift/codegen/qlgen.py b/swift/codegen/qlgen.py index ad44a234c77..5d08f5a0410 100755 --- a/swift/codegen/qlgen.py +++ b/swift/codegen/qlgen.py @@ -107,7 +107,8 @@ def generate(opts, renderer): renderer.render(all_imports, include_file) renderer.cleanup(existing) - format(opts.codeql_binary, renderer.written) + if opts.ql_format: + format(opts.codeql_binary, renderer.written) tags = ("schema", "ql") diff --git a/swift/codegen/test/test_qlgen.py b/swift/codegen/test/test_qlgen.py index 8affd50fb7f..d273539e375 100644 --- a/swift/codegen/test/test_qlgen.py +++ b/swift/codegen/test/test_qlgen.py @@ -23,6 +23,7 @@ gen_import_prefix = "other.path." def generate(opts, renderer, written=None): opts.ql_stub_output = stub_path() opts.ql_output = ql_output_path() + opts.ql_format = True renderer.written = written or [] return run_generation(qlgen.generate, opts, renderer) From 36f56b5a189c8095d2821fe806525c2ce5ca4c83 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sun, 8 May 2022 17:02:12 +0200 Subject: [PATCH 136/171] Java: Rename `StmtExpr` to `ValueDiscardingExpr` As mentioned by aschackmull during review, StatementExpression as defined by the JLS only lists possible types of expressions, it does _not_ specify that their value is discarded. Therefore, for example any method call could be considered a StatementExpression. The name ValueDiscardingExpr was chosen as replacement because the JLS uses the phrase "if the expression has a value, the value is discarded" multiple times. --- .../2022-03-27-statement-expression.md | 4 - .../2022-05-09-value-discarding-expression.md | 4 + java/ql/lib/semmle/code/java/Collections.qll | 2 +- java/ql/lib/semmle/code/java/Expr.qll | 69 ++++++------ java/ql/lib/semmle/code/java/Maps.qll | 2 +- .../Statements/ReturnValueIgnored.ql | 2 +- .../IgnoreExceptionalReturn.ql | 2 +- .../CWE-297/IgnoredHostnameVerification.ql | 2 +- .../library-tests/StmtExpr/StmtExpr.expected | 14 --- .../test/library-tests/StmtExpr/StmtExpr.java | 68 ------------ .../test/library-tests/StmtExpr/StmtExpr.ql | 4 - .../ValueDiscardingExpr.expected | 16 +++ .../ValueDiscardingExpr.java | 100 ++++++++++++++++++ .../ValueDiscardingExpr.ql | 4 + .../{StmtExpr => ValueDiscardingExpr}/options | 0 15 files changed, 167 insertions(+), 126 deletions(-) delete mode 100644 java/ql/lib/change-notes/2022-03-27-statement-expression.md create mode 100644 java/ql/lib/change-notes/2022-05-09-value-discarding-expression.md delete mode 100644 java/ql/test/library-tests/StmtExpr/StmtExpr.expected delete mode 100644 java/ql/test/library-tests/StmtExpr/StmtExpr.java delete mode 100644 java/ql/test/library-tests/StmtExpr/StmtExpr.ql create mode 100644 java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.expected create mode 100644 java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.java create mode 100644 java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.ql rename java/ql/test/library-tests/{StmtExpr => ValueDiscardingExpr}/options (100%) diff --git a/java/ql/lib/change-notes/2022-03-27-statement-expression.md b/java/ql/lib/change-notes/2022-03-27-statement-expression.md deleted file mode 100644 index bb261f66878..00000000000 --- a/java/ql/lib/change-notes/2022-03-27-statement-expression.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: feature ---- -* The QL class `StmtExpr` has been added to model statement expressions, that is, expressions whose result is discarded. diff --git a/java/ql/lib/change-notes/2022-05-09-value-discarding-expression.md b/java/ql/lib/change-notes/2022-05-09-value-discarding-expression.md new file mode 100644 index 00000000000..36adb0169d4 --- /dev/null +++ b/java/ql/lib/change-notes/2022-05-09-value-discarding-expression.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* The QL class `ValueDiscardingExpr` has been added, representing expressions for which the value of the expression as a whole is discarded. diff --git a/java/ql/lib/semmle/code/java/Collections.qll b/java/ql/lib/semmle/code/java/Collections.qll index e6da65faa04..1f4c25ed532 100644 --- a/java/ql/lib/semmle/code/java/Collections.qll +++ b/java/ql/lib/semmle/code/java/Collections.qll @@ -84,7 +84,7 @@ class CollectionMutation extends MethodAccess { CollectionMutation() { this.getMethod() instanceof CollectionMutator } /** Holds if the result of this call is not immediately discarded. */ - predicate resultIsChecked() { not this instanceof StmtExpr } + predicate resultIsChecked() { not this instanceof ValueDiscardingExpr } } /** A method that queries the contents of a collection without mutating it. */ diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index 1e6b14fc9e7..e9332fd68af 100755 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -2135,38 +2135,45 @@ class Argument extends Expr { } /** - * A statement expression, as specified by JLS 17 section 14.8. - * The result of a statement expression, if any, is discarded. + * An expression for which the value of the expression as a whole is discarded. Only cases + * of discarded values at the language level (as described by the JLS) are considered; + * data flow, for example to determine if an assigned variable value is ever read, is not + * considered. Such expressions can for example appear as part of an `ExprStmt` or as + * initializer of a `for` loop. * - * Not to be confused with `ExprStmt`; while the child of an `ExprStmt` is always - * a `StmtExpr`, the opposite is not true. A `StmtExpr` occurs for example also - * as 'init' of a `for` statement. + * For example, for the statement `i++;` the value of the increment expression, that is the + * old value of variable `i`, is discarded. Whereas for the statement `println(i++);` the + * value of the increment expression is not discarded but used as argument for the method call. */ -class StmtExpr extends Expr { - StmtExpr() { - this = any(ExprStmt s).getExpr() - or - this = any(ForStmt s).getAnInit() and not this instanceof LocalVariableDeclExpr - or - this = any(ForStmt s).getAnUpdate() - or - // Only applies to SwitchStmt, but not to SwitchExpr, see JLS 17 section 14.11.2 - this = any(SwitchStmt s).getACase().getRuleExpression() - or - // TODO: Workarounds for https://github.com/github/codeql/issues/3605 - exists(LambdaExpr lambda | - this = lambda.getExprBody() and - lambda.asMethod().getReturnType() instanceof VoidType - ) - or - exists(MemberRefExpr memberRef, Method implicitMethod, Method overridden | - implicitMethod = memberRef.asMethod() - | - this.getParent().(ReturnStmt).getEnclosingCallable() = implicitMethod and - // asMethod() has bogus method with wrong return type as result, e.g. `run(): String` (overriding `Runnable.run(): void`) - // Therefore need to check the overridden method - implicitMethod.getSourceDeclaration().overridesOrInstantiates*(overridden) and - overridden.getReturnType() instanceof VoidType - ) +class ValueDiscardingExpr extends Expr { + ValueDiscardingExpr() { + ( + this = any(ExprStmt s).getExpr() + or + this = any(ForStmt s).getAnInit() and not this instanceof LocalVariableDeclExpr + or + this = any(ForStmt s).getAnUpdate() + or + // Only applies to SwitchStmt, but not to SwitchExpr, see JLS 17 section 14.11.2 + this = any(SwitchStmt s).getACase().getRuleExpression() + or + // TODO: Workarounds for https://github.com/github/codeql/issues/3605 + exists(LambdaExpr lambda | + this = lambda.getExprBody() and + lambda.asMethod().getReturnType() instanceof VoidType + ) + or + exists(MemberRefExpr memberRef, Method implicitMethod, Method overridden | + implicitMethod = memberRef.asMethod() + | + this.getParent().(ReturnStmt).getEnclosingCallable() = implicitMethod and + // asMethod() has bogus method with wrong return type as result, e.g. `run(): String` (overriding `Runnable.run(): void`) + // Therefore need to check the overridden method + implicitMethod.getSourceDeclaration().overridesOrInstantiates*(overridden) and + overridden.getReturnType() instanceof VoidType + ) + ) and + // Ignore if this expression is a method call with `void` as return type + not getType() instanceof VoidType } } diff --git a/java/ql/lib/semmle/code/java/Maps.qll b/java/ql/lib/semmle/code/java/Maps.qll index f768ee3642b..6ff61616f4b 100644 --- a/java/ql/lib/semmle/code/java/Maps.qll +++ b/java/ql/lib/semmle/code/java/Maps.qll @@ -53,7 +53,7 @@ class MapMutation extends MethodAccess { MapMutation() { this.getMethod() instanceof MapMutator } /** Holds if the result of this call is not immediately discarded. */ - predicate resultIsChecked() { not this instanceof StmtExpr } + predicate resultIsChecked() { not this instanceof ValueDiscardingExpr } } /** A method that queries the contents of the map it belongs to without mutating it. */ diff --git a/java/ql/src/Likely Bugs/Statements/ReturnValueIgnored.ql b/java/ql/src/Likely Bugs/Statements/ReturnValueIgnored.ql index 1c2905c1d61..3355fd22190 100644 --- a/java/ql/src/Likely Bugs/Statements/ReturnValueIgnored.ql +++ b/java/ql/src/Likely Bugs/Statements/ReturnValueIgnored.ql @@ -18,7 +18,7 @@ import Chaining predicate checkedMethodCall(MethodAccess ma) { relevantMethodCall(ma, _) and - not ma instanceof StmtExpr + not ma instanceof ValueDiscardingExpr } /** diff --git a/java/ql/src/Violations of Best Practice/Exception Handling/IgnoreExceptionalReturn.ql b/java/ql/src/Violations of Best Practice/Exception Handling/IgnoreExceptionalReturn.ql index ed712eb2504..5a03dafa673 100644 --- a/java/ql/src/Violations of Best Practice/Exception Handling/IgnoreExceptionalReturn.ql +++ b/java/ql/src/Violations of Best Practice/Exception Handling/IgnoreExceptionalReturn.ql @@ -45,7 +45,7 @@ predicate unboundedQueue(RefType t) { from MethodAccess ma, SpecialMethod m where - ma instanceof StmtExpr and + ma instanceof ValueDiscardingExpr and m = ma.getMethod() and ( m.isMethod("java.util", "Queue", "offer", 1) and not unboundedQueue(m.getDeclaringType()) diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql b/java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql index 38e2cb79998..c4bb1192f2b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql @@ -21,7 +21,7 @@ private class HostnameVerificationCall extends MethodAccess { } /** Holds if the result of the call is not used. */ - predicate isIgnored() { this instanceof StmtExpr } + predicate isIgnored() { this instanceof ValueDiscardingExpr } } from HostnameVerificationCall verification diff --git a/java/ql/test/library-tests/StmtExpr/StmtExpr.expected b/java/ql/test/library-tests/StmtExpr/StmtExpr.expected deleted file mode 100644 index ecb5e338238..00000000000 --- a/java/ql/test/library-tests/StmtExpr/StmtExpr.expected +++ /dev/null @@ -1,14 +0,0 @@ -| StmtExpr.java:7:9:7:18 | toString(...) | -| StmtExpr.java:13:9:13:13 | ...=... | -| StmtExpr.java:14:9:14:11 | ...++ | -| StmtExpr.java:15:9:15:11 | ++... | -| StmtExpr.java:16:9:16:11 | ...-- | -| StmtExpr.java:17:9:17:11 | --... | -| StmtExpr.java:19:9:19:20 | new Object(...) | -| StmtExpr.java:22:9:22:28 | clone(...) | -| StmtExpr.java:25:14:25:39 | println(...) | -| StmtExpr.java:30:17:30:44 | println(...) | -| StmtExpr.java:45:24:45:33 | toString(...) | -| StmtExpr.java:58:28:58:37 | toString(...) | -| StmtExpr.java:60:13:60:22 | toString(...) | -| StmtExpr.java:66:23:66:36 | toString(...) | diff --git a/java/ql/test/library-tests/StmtExpr/StmtExpr.java b/java/ql/test/library-tests/StmtExpr/StmtExpr.java deleted file mode 100644 index c35e24ea122..00000000000 --- a/java/ql/test/library-tests/StmtExpr/StmtExpr.java +++ /dev/null @@ -1,68 +0,0 @@ -package StmtExpr; - -import java.util.function.Supplier; - -class StmtExpr { - void test() { - toString(); - - // LocalVariableDeclarationStatement with init is not a StatementExpression - String s = toString(); - - int i; - i = 0; - i++; - ++i; - i--; - --i; - - new Object(); - // ArrayCreationExpression cannot be a StatementExpression, but a method access - // on it can be - new int[] {}.clone(); - - // for statement init can be StatementExpression - for (System.out.println("init");;) { - break; - } - - // for statement update is StatementExpression - for (;; System.out.println("update")) { - break; - } - - // variable declaration and condition are not StatementExpressions - for (int i1 = 0; i1 < 10;) { } - for (int i1, i2 = 0; i2 < 10;) { } - for (;;) { - break; - } - - // Not a StatementExpression - for (int i2 : new int[] {1}) { } - - switch(1) { - default -> toString(); // StatementExpression - } - // SwitchExpression has no StatementExpression - String s2 = switch(1) { - default -> toString(); - }; - - // Lambda with non-void return type has no StatementExpression - Supplier supplier1 = () -> toString(); - Supplier supplier2 = () -> { - return toString(); - }; - // Lambda with void return type has StatementExpression - Runnable r = () -> toString(); - Runnable r2 = () -> { - toString(); - }; - - // Method reference with non-void return type has no StatementExpression - Supplier supplier3 = StmtExpr::new; - // Method reference with void return type has StatementExpression in implicit method body - Runnable r3 = this::toString; - } -} diff --git a/java/ql/test/library-tests/StmtExpr/StmtExpr.ql b/java/ql/test/library-tests/StmtExpr/StmtExpr.ql deleted file mode 100644 index c624e738d71..00000000000 --- a/java/ql/test/library-tests/StmtExpr/StmtExpr.ql +++ /dev/null @@ -1,4 +0,0 @@ -import java - -from StmtExpr e -select e diff --git a/java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.expected b/java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.expected new file mode 100644 index 00000000000..6a512fcdf32 --- /dev/null +++ b/java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.expected @@ -0,0 +1,16 @@ +| ValueDiscardingExpr.java:9:9:9:18 | toString(...) | +| ValueDiscardingExpr.java:18:9:18:13 | ...=... | +| ValueDiscardingExpr.java:19:9:19:11 | ...++ | +| ValueDiscardingExpr.java:20:9:20:11 | ++... | +| ValueDiscardingExpr.java:21:9:21:11 | ...-- | +| ValueDiscardingExpr.java:22:9:22:11 | --... | +| ValueDiscardingExpr.java:24:9:24:20 | new Object(...) | +| ValueDiscardingExpr.java:27:9:27:28 | clone(...) | +| ValueDiscardingExpr.java:30:14:30:38 | append(...) | +| ValueDiscardingExpr.java:35:17:35:43 | append(...) | +| ValueDiscardingExpr.java:55:24:55:33 | toString(...) | +| ValueDiscardingExpr.java:74:29:74:38 | toString(...) | +| ValueDiscardingExpr.java:76:13:76:22 | toString(...) | +| ValueDiscardingExpr.java:90:23:90:35 | new StmtExpr(...) | +| ValueDiscardingExpr.java:91:23:91:36 | toString(...) | +| ValueDiscardingExpr.java:95:25:95:37 | new String[] | diff --git a/java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.java b/java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.java new file mode 100644 index 00000000000..3dc9fbce8fa --- /dev/null +++ b/java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.java @@ -0,0 +1,100 @@ +package StmtExpr; + +import java.util.function.IntConsumer; +import java.util.function.IntFunction; +import java.util.function.Supplier; + +class StmtExpr { + void test() { + toString(); + + // Method call with `void` return type is not a ValueDiscardingExpr + System.out.println("test"); + + // LocalVariableDeclarationStatement with init is not a ValueDiscardingExpr + String s = toString(); + + int i; + i = 0; + i++; + ++i; + i--; + --i; + + new Object(); + // Language specification does not permit ArrayCreationExpression at locations where its + // value would be discard, but the value of a method access on it can be discarded + new int[] {}.clone(); + + // for statement init can discard value + for (System.out.append("init");;) { + break; + } + + // for statement update discards value + for (;; System.out.append("update")) { + break; + } + + // Method call with `void` return type is not a ValueDiscardingExpr + for (;; System.out.println("update")) { + break; + } + + // variable declaration and condition are not ValueDiscardingExpr + for (int i1 = 0; i1 < 10;) { } + for (int i1, i2 = 0; i2 < 10;) { } + for (;;) { + break; + } + + // Not a ValueDiscardingExpr + for (int i2 : new int[] {1}) { } + + switch(1) { + default -> toString(); // ValueDiscardingExpr + } + + switch(1) { + // Method call with `void` return type is not a ValueDiscardingExpr + default -> System.out.println(); + } + + String s2 = switch(1) { + // Expression in SwitchExpression case rule is not a ValueDiscardingExpr + default -> toString(); + }; + + // Expression in lambda with non-void return type is not a ValueDiscardingExpr + Supplier supplier1 = () -> toString(); + Supplier supplier2 = () -> { + return toString(); + }; + // Expression in lambda with void return type is ValueDiscardingExpr + Runnable r1 = () -> toString(); + Runnable r2 = () -> { + toString(); + }; + // Lambda with method call with `void` return type is not a ValueDiscardingExpr + Runnable r3 = () -> System.out.println(); + Runnable r4 = () -> { + System.out.println(); + }; + + // Method reference with non-void return type has no ValueDiscardingExpr + Supplier supplier3 = StmtExpr::new; + IntFunction f = String[]::new; + Supplier supplier4 = this::toString; + + // Method reference with void return type has ValueDiscardingExpr in implicit method body + Runnable r5 = StmtExpr::new; + Runnable r6 = this::toString; + // Interestingly a method reference expression with function type (int)->void allows usage of + // array creation expressions, even though a regular StatementExpression would not allow it, + // for example the ExpressionStatement `new String[1];` is not allowed by the JLS + IntConsumer c = String[]::new; + + // Method reference referring to method with `void` return type is not a ValueDiscardingExpr + Runnable r7 = System.out::println; + } +} diff --git a/java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.ql b/java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.ql new file mode 100644 index 00000000000..59b32c09a7f --- /dev/null +++ b/java/ql/test/library-tests/ValueDiscardingExpr/ValueDiscardingExpr.ql @@ -0,0 +1,4 @@ +import java + +from ValueDiscardingExpr e +select e diff --git a/java/ql/test/library-tests/StmtExpr/options b/java/ql/test/library-tests/ValueDiscardingExpr/options similarity index 100% rename from java/ql/test/library-tests/StmtExpr/options rename to java/ql/test/library-tests/ValueDiscardingExpr/options From 6cbfb5a10c2a0158c6d166ad6d82088b383eaac9 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Mon, 9 May 2022 09:02:20 +0200 Subject: [PATCH 137/171] Swift cppgen: emit final trap before bases --- swift/codegen/templates/cpp_classes.mustache | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/swift/codegen/templates/cpp_classes.mustache b/swift/codegen/templates/cpp_classes.mustache index 4dddf4dab06..06c7b8d062a 100644 --- a/swift/codegen/templates/cpp_classes.mustache +++ b/swift/codegen/templates/cpp_classes.mustache @@ -26,12 +26,12 @@ struct {{name}}{{#final}} : Binding<{{name}}Tag>{{#bases}}, {{ref.name}}{{/bases protected: void emit({{^final}}TrapLabel<{{name}}Tag> id, {{/final}}std::ostream& out) const { - {{#bases}} - {{ref.name}}::emit(id, out); - {{/bases}} {{#trap_name}} out << {{.}}{{trap_affix}}{id{{#single_fields}}, {{name}}{{/single_fields}}} << '\n'; {{/trap_name}} + {{#bases}} + {{ref.name}}::emit(id, out); + {{/bases}} {{#fields}} {{#is_optional}} {{^is_repeated}} From 918ba1b1fc68ca292634646caf3727a5945e5fa9 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Mon, 9 May 2022 09:34:49 +0200 Subject: [PATCH 138/171] Swift: make generator.run accept options --- swift/codegen/lib/generator.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/swift/codegen/lib/generator.py b/swift/codegen/lib/generator.py index 9c0a071cefa..bcb05182aef 100644 --- a/swift/codegen/lib/generator.py +++ b/swift/codegen/lib/generator.py @@ -3,26 +3,29 @@ import argparse import logging import sys +from typing import Set from . import options, render -def _parse(tags): +def _parse(tags: Set[str]) -> argparse.Namespace: parser = argparse.ArgumentParser() for opt in options.get(tags): opt.add_to(parser) - ret = parser.parse_args() - log_level = logging.DEBUG if ret.verbose else logging.INFO - logging.basicConfig(format="{levelname} {message}", style='{', level=log_level) - return ret + return parser.parse_args() -def run(*modules): +def run(*modules, **kwargs): """ run generation functions in specified in `modules`, or in current module by default """ if modules: - opts = _parse({t for m in modules for t in m.tags}) + if kwargs: + opts = argparse.Namespace(**kwargs) + else: + opts = _parse({t for m in modules for t in m.tags}) + log_level = logging.DEBUG if opts.verbose else logging.INFO + logging.basicConfig(format="{levelname} {message}", style='{', level=log_level) for m in modules: m.generate(opts, render.Renderer()) else: - run(sys.modules["__main__"]) + run(sys.modules["__main__"], **kwargs) From 9c5b2d7e9dd1fcca9c1b15b9749c9fe7dcc088d4 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Mon, 9 May 2022 09:46:47 +0200 Subject: [PATCH 139/171] Swift: tweaks for use in the PoC branch --- swift/codegen/lib/generator.py | 5 +++-- swift/codegen/lib/paths.py | 5 +---- swift/codegen/lib/render.py | 5 +++-- swift/codegen/templates/ql_class.mustache | 1 + swift/codegen/templates/ql_stub.mustache | 3 ++- swift/codegen/test/test_render.py | 7 +++++-- swift/codegen/test/utils.py | 2 +- 7 files changed, 16 insertions(+), 12 deletions(-) diff --git a/swift/codegen/lib/generator.py b/swift/codegen/lib/generator.py index bcb05182aef..c78d8e3b523 100644 --- a/swift/codegen/lib/generator.py +++ b/swift/codegen/lib/generator.py @@ -5,7 +5,7 @@ import logging import sys from typing import Set -from . import options, render +from . import options, render, paths def _parse(tags: Set[str]) -> argparse.Namespace: @@ -25,7 +25,8 @@ def run(*modules, **kwargs): opts = _parse({t for m in modules for t in m.tags}) log_level = logging.DEBUG if opts.verbose else logging.INFO logging.basicConfig(format="{levelname} {message}", style='{', level=log_level) + exe_path = paths.exe_file.relative_to(opts.swift_dir) for m in modules: - m.generate(opts, render.Renderer()) + m.generate(opts, render.Renderer(exe_path)) else: run(sys.modules["__main__"], **kwargs) diff --git a/swift/codegen/lib/paths.py b/swift/codegen/lib/paths.py index 8fe63cefe8e..2ad1284b17b 100644 --- a/swift/codegen/lib/paths.py +++ b/swift/codegen/lib/paths.py @@ -15,7 +15,4 @@ except KeyError: lib_dir = swift_dir / 'codegen' / 'lib' templates_dir = swift_dir / 'codegen' / 'templates' -try: - exe_file = pathlib.Path(sys.argv[0]).resolve().relative_to(swift_dir) -except ValueError: - exe_file = pathlib.Path(sys.argv[0]).name +exe_file = pathlib.Path(sys.argv[0]).resolve() diff --git a/swift/codegen/lib/render.py b/swift/codegen/lib/render.py index 3d20fe1a199..b8fae984c67 100644 --- a/swift/codegen/lib/render.py +++ b/swift/codegen/lib/render.py @@ -18,9 +18,10 @@ log = logging.getLogger(__name__) class Renderer: """ Template renderer using mustache templates in the `templates` directory """ - def __init__(self): + def __init__(self, generator): self._r = pystache.Renderer(search_dirs=str(paths.templates_dir), escape=lambda u: u) self.written = set() + self._generator = generator def render(self, data, output: pathlib.Path): """ Render `data` to `output`. @@ -34,7 +35,7 @@ class Renderer: """ mnemonic = type(data).__name__ output.parent.mkdir(parents=True, exist_ok=True) - data = self._r.render_name(data.template, data, generator=paths.exe_file) + data = self._r.render_name(data.template, data, generator=self._generator) with open(output, "w") as out: out.write(data) log.debug(f"generated {mnemonic} {output.name}") diff --git a/swift/codegen/templates/ql_class.mustache b/swift/codegen/templates/ql_class.mustache index e2f2a6a449f..12ca76c9975 100644 --- a/swift/codegen/templates/ql_class.mustache +++ b/swift/codegen/templates/ql_class.mustache @@ -1,4 +1,5 @@ // generated by {{generator}} + {{#imports}} import {{.}} {{/imports}} diff --git a/swift/codegen/templates/ql_stub.mustache b/swift/codegen/templates/ql_stub.mustache index adc16b362c9..198e0f4dd51 100644 --- a/swift/codegen/templates/ql_stub.mustache +++ b/swift/codegen/templates/ql_stub.mustache @@ -1,4 +1,5 @@ // generated by {{generator}}, remove this comment if you wish to edit this file + private import {{base_import}} -class {{name}} extends {{name}}Base { } +class {{name}} extends {{name}}Base {} diff --git a/swift/codegen/test/test_render.py b/swift/codegen/test/test_render.py index ea007a54563..adb823a2bab 100644 --- a/swift/codegen/test/test_render.py +++ b/swift/codegen/test/test_render.py @@ -7,6 +7,9 @@ from swift.codegen.lib import paths from swift.codegen.lib import render +generator = "test/foogen" + + @pytest.fixture def pystache_renderer_cls(): with mock.patch("pystache.Renderer") as ret: @@ -22,7 +25,7 @@ def pystache_renderer(pystache_renderer_cls): @pytest.fixture def sut(pystache_renderer): - return render.Renderer() + return render.Renderer(generator) def test_constructor(pystache_renderer_cls, sut): @@ -40,7 +43,7 @@ def test_render(pystache_renderer, sut): with mock.patch("builtins.open", mock.mock_open()) as output_stream: sut.render(data, output) assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file), + mock.call.render_name(data.template, data, generator=generator), ] assert output_stream.mock_calls == [ mock.call(output, 'w'), diff --git a/swift/codegen/test/utils.py b/swift/codegen/test/utils.py index bf646297af5..231489e04e4 100644 --- a/swift/codegen/test/utils.py +++ b/swift/codegen/test/utils.py @@ -18,7 +18,7 @@ def write(out, contents=""): @pytest.fixture def renderer(): - return mock.Mock(spec=render.Renderer()) + return mock.Mock(spec=render.Renderer("")) @pytest.fixture From f5854f33da4a51c39e4a6bccb778393d92e29efe Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 9 May 2022 10:53:25 +0200 Subject: [PATCH 140/171] Python: Apply suggestions from code review Co-authored-by: yoff --- python/ql/src/Security/CWE-776/XmlBomb.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Security/CWE-776/XmlBomb.qhelp b/python/ql/src/Security/CWE-776/XmlBomb.qhelp index f20dd526fdd..8841f98ab27 100644 --- a/python/ql/src/Security/CWE-776/XmlBomb.qhelp +++ b/python/ql/src/Security/CWE-776/XmlBomb.qhelp @@ -39,7 +39,7 @@ PyPI package, which has been created to prevent XML attacks (both XXE and XML bo

    The following example uses the xml.etree XML parser provided by the Python standard library to -parse a string xml_src. That string is from an untrusted source, so this code is be +parse a string xml_src. That string is from an untrusted source, so this code is vulnerable to a DoS attack, since the xml.etree XML parser expands internal entities by default:

    From f22bd039f3014cb00e2f6211b686f5b2fc9198fd Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 9 May 2022 10:56:39 +0200 Subject: [PATCH 141/171] Python: Slight refactor of `LxmlParsing` --- python/ql/lib/semmle/python/frameworks/Lxml.qll | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index cfb83fd5732..70e46a6d3b0 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -235,12 +235,11 @@ private module Lxml { * - https://lxml.de/apidoc/lxml.etree.html?highlight=parseids#lxml.etree.parseid */ private class LxmlParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { + string functionName; + LxmlParsing() { - this = - API::moduleImport("lxml") - .getMember("etree") - .getMember(["fromstring", "fromstringlist", "XML", "XMLID", "parse", "parseid"]) - .getACall() + functionName in ["fromstring", "fromstringlist", "XML", "XMLID", "parse", "parseid"] and + this = API::moduleImport("lxml").getMember("etree").getMember(functionName).getACall() } override DataFlow::Node getAnInput() { @@ -287,7 +286,7 @@ private module Lxml { */ private class FileAccessFromLxmlParsing extends LxmlParsing, FileSystemAccess::Range { FileAccessFromLxmlParsing() { - this = API::moduleImport("lxml").getMember("etree").getMember(["parse", "parseid"]).getACall() + functionName in ["parse", "parseid"] // I considered whether we should try to reduce FPs from people passing file-like // objects, which will not be a file system access (and couldn't cause a // path-injection). From 36349222a9561c6996fbd6f2e30ab8580313e5ac Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 9 May 2022 11:00:25 +0200 Subject: [PATCH 142/171] Python: Fix casing of `XMLDomParsing` --- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index bf2b01930d2..e67e90cc794 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3591,8 +3591,8 @@ private module StdlibPrivate { * - https://docs.python.org/3/library/xml.dom.minidom.html#xml.dom.minidom.parse * - https://docs.python.org/3/library/xml.dom.pulldom.html#xml.dom.pulldom.parse */ - private class XMLDomParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { - XMLDomParsing() { + private class XmlDomParsing extends DataFlow::CallCfgNode, XML::XmlParsing::Range { + XmlDomParsing() { this = API::moduleImport("xml") .getMember("dom") @@ -3636,8 +3636,8 @@ private module StdlibPrivate { * - https://docs.python.org/3/library/xml.dom.minidom.html#xml.dom.minidom.parse * - https://docs.python.org/3/library/xml.dom.pulldom.html#xml.dom.pulldom.parse */ - private class FileAccessFromXMLDomParsing extends XMLDomParsing, FileSystemAccess::Range { - FileAccessFromXMLDomParsing() { + private class FileAccessFromXmlDomParsing extends XmlDomParsing, FileSystemAccess::Range { + FileAccessFromXmlDomParsing() { this = API::moduleImport("xml") .getMember("dom") From de05b108faaa469952bf8d83cfa0f2b5d6e086b4 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 9 May 2022 11:01:13 +0200 Subject: [PATCH 143/171] Python: Fix singleton set --- python/ql/test/experimental/meta/ConceptsTest.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 73bcf8b4aa9..7b8649b7abb 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -543,7 +543,7 @@ class HttpClientRequestTest extends InlineExpectationsTest { class XmlParsingTest extends InlineExpectationsTest { XmlParsingTest() { this = "XmlParsingTest" } - override string getARelevantTag() { result in ["xmlVuln"] } + override string getARelevantTag() { result = "xmlVuln" } override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and From 88b5bbe02454ec43f80dd1198472bb61cb6ee7d1 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 9 May 2022 11:55:07 +0200 Subject: [PATCH 144/171] JS: Update test expectation --- .../ql/test/library-tests/TypeTracking/PredicateStyle.expected | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/ql/test/library-tests/TypeTracking/PredicateStyle.expected b/javascript/ql/test/library-tests/TypeTracking/PredicateStyle.expected index 5aef5c84540..17ccc170403 100644 --- a/javascript/ql/test/library-tests/TypeTracking/PredicateStyle.expected +++ b/javascript/ql/test/library-tests/TypeTracking/PredicateStyle.expected @@ -44,7 +44,6 @@ connection | type tracker without call steps | tst.js:120:21:120:24 | conn | | type tracker without call steps | tst.js:126:22:126:25 | conn | | type tracker without call steps | tst_conflict.js:6:38:6:77 | api.cha ... ction() | -| type tracker without call steps with property MyApplication.namespace.connection | file://:0:0:0:0 | global access path | | type tracker without call steps with property conflict | tst.js:63:3:63:25 | MyAppli ... mespace | | type tracker without call steps with property conflict | tst_conflict.js:6:3:6:25 | MyAppli ... mespace | | type tracker without call steps with property connection | tst.js:62:3:62:25 | MyAppli ... mespace | From 20317a280b8403b0169678a44f56714386846a88 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Mon, 9 May 2022 10:04:18 +0200 Subject: [PATCH 145/171] Swift: make `width` fields `unsigned` --- swift/codegen/lib/cpp.py | 2 +- swift/codegen/test/test_cppgen.py | 59 ++++++++++++++++--------------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/swift/codegen/lib/cpp.py b/swift/codegen/lib/cpp.py index 7e360fcddf6..886ef8069e6 100644 --- a/swift/codegen/lib/cpp.py +++ b/swift/codegen/lib/cpp.py @@ -16,7 +16,7 @@ cpp_keywords = {"alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", " "xor", "xor_eq"} _field_overrides = [ - (re.compile(r"(start|end)_(line|column)|index|num_.*"), {"type": "unsigned"}), + (re.compile(r"(start|end)_(line|column)|index|width|num_.*"), {"type": "unsigned"}), (re.compile(r"(.*)_"), lambda m: {"name": m[1]}), ] diff --git a/swift/codegen/test/test_cppgen.py b/swift/codegen/test/test_cppgen.py index b47a1159df1..ac37b7300c5 100644 --- a/swift/codegen/test/test_cppgen.py +++ b/swift/codegen/test/test_cppgen.py @@ -36,8 +36,8 @@ def test_empty_class(generate): assert generate([ schema.Class(name="MyClass"), ]) == [ - cpp.Class(name="MyClass", final=True, trap_name="MyClasses") - ] + cpp.Class(name="MyClass", final=True, trap_name="MyClasses") + ] def test_two_class_hierarchy(generate): @@ -46,9 +46,9 @@ def test_two_class_hierarchy(generate): schema.Class(name="A", derived={"B"}), schema.Class(name="B", bases={"A"}), ]) == [ - base, - cpp.Class(name="B", bases=[base], final=True, trap_name="Bs"), - ] + base, + cpp.Class(name="B", bases=[base], final=True, trap_name="Bs"), + ] def test_complex_hierarchy_topologically_ordered(generate): @@ -84,37 +84,38 @@ def test_class_with_field(generate, type, expected, property_cls, optional, repe assert generate([ schema.Class(name="MyClass", properties=[property_cls("prop", type)]), ]) == [ - cpp.Class(name="MyClass", - fields=[cpp.Field("prop", expected, is_optional=optional, - is_repeated=repeated, trap_name=trap_name)], - trap_name="MyClasses", - final=True) - ] + cpp.Class(name="MyClass", + fields=[cpp.Field("prop", expected, is_optional=optional, + is_repeated=repeated, trap_name=trap_name)], + trap_name="MyClasses", + final=True) + ] -@pytest.mark.parametrize("name", ["start_line", "start_column", "end_line", "end_column", "index", "num_whatever"]) +@pytest.mark.parametrize("name", + ["start_line", "start_column", "end_line", "end_column", "index", "num_whatever", "width"]) def test_class_with_overridden_unsigned_field(generate, name): assert generate([ schema.Class(name="MyClass", properties=[ - schema.SingleProperty(name, "bar")]), + schema.SingleProperty(name, "bar")]), ]) == [ - cpp.Class(name="MyClass", - fields=[cpp.Field(name, "unsigned")], - trap_name="MyClasses", - final=True) - ] + cpp.Class(name="MyClass", + fields=[cpp.Field(name, "unsigned")], + trap_name="MyClasses", + final=True) + ] def test_class_with_overridden_underscore_field(generate): assert generate([ schema.Class(name="MyClass", properties=[ - schema.SingleProperty("something_", "bar")]), + schema.SingleProperty("something_", "bar")]), ]) == [ - cpp.Class(name="MyClass", - fields=[cpp.Field("something", "bar")], - trap_name="MyClasses", - final=True) - ] + cpp.Class(name="MyClass", + fields=[cpp.Field("something", "bar")], + trap_name="MyClasses", + final=True) + ] @pytest.mark.parametrize("name", cpp.cpp_keywords) @@ -123,11 +124,11 @@ def test_class_with_keyword_field(generate, name): schema.Class(name="MyClass", properties=[ schema.SingleProperty(name, "bar")]), ]) == [ - cpp.Class(name="MyClass", - fields=[cpp.Field(name + "_", "bar")], - trap_name="MyClasses", - final=True) - ] + cpp.Class(name="MyClass", + fields=[cpp.Field(name + "_", "bar")], + trap_name="MyClasses", + final=True) + ] if __name__ == '__main__': From 93f8b6b29d4752924afabd7424147459ebdb44d1 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Mon, 9 May 2022 12:19:02 +0200 Subject: [PATCH 146/171] Swift: add missing `trap_affix` --- swift/codegen/templates/cpp_classes.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/codegen/templates/cpp_classes.mustache b/swift/codegen/templates/cpp_classes.mustache index 06c7b8d062a..3e9d12084c9 100644 --- a/swift/codegen/templates/cpp_classes.mustache +++ b/swift/codegen/templates/cpp_classes.mustache @@ -25,7 +25,7 @@ struct {{name}}{{#final}} : Binding<{{name}}Tag>{{#bases}}, {{ref.name}}{{/bases {{/final}} protected: - void emit({{^final}}TrapLabel<{{name}}Tag> id, {{/final}}std::ostream& out) const { + void emit({{^final}}{{trap_affix}}Label<{{name}}Tag> id, {{/final}}std::ostream& out) const { {{#trap_name}} out << {{.}}{{trap_affix}}{id{{#single_fields}}, {{name}}{{/single_fields}}} << '\n'; {{/trap_name}} From 804ca3e1a73c772b11455fb2bf54a8cecee3441d Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Mon, 9 May 2022 11:29:53 +0100 Subject: [PATCH 147/171] Actions: Fetch CodeQL CLI using `gh` rather than third-party Action --- .github/workflows/query-list.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/query-list.yml b/.github/workflows/query-list.yml index c6ff0aa1153..6bd1d3a5bf3 100644 --- a/.github/workflows/query-list.yml +++ b/.github/workflows/query-list.yml @@ -30,20 +30,14 @@ jobs: with: python-version: 3.8 - name: Download CodeQL CLI - uses: dsaltares/fetch-gh-release-asset@aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c - with: - repo: "github/codeql-cli-binaries" - version: "latest" - file: "codeql-linux64.zip" - token: ${{ secrets.GITHUB_TOKEN }} + uses: ./codeql/.github/actions/fetch-codeql - name: Unzip CodeQL CLI run: unzip -d codeql-cli codeql-linux64.zip - name: Build code scanning query list run: | - PATH="$PATH:codeql-cli/codeql" python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv + python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv - name: Upload code scanning query list uses: actions/upload-artifact@v3 with: name: code-scanning-query-list path: code-scanning-query-list.csv - From 9709c2fa94644f3e0c992c07fa3f8875cecf9da6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 9 May 2022 11:58:17 +0100 Subject: [PATCH 148/171] C++: Use compliant PascalCase / make the checks happy. --- cpp/ql/src/Security/CWE/CWE-611/XXE.ql | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql index 413bcfa04f1..7daea2f1d63 100644 --- a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql +++ b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql @@ -60,15 +60,15 @@ class XercesDOMParserClass extends Class { /** * The `SAXParser` class. */ -class SAXParserClass extends Class { - SAXParserClass() { this.hasName("SAXParser") } +class SaxParserClass extends Class { + SaxParserClass() { this.hasName("SAXParser") } } /** * The `SAX2XMLReader` class. */ -class SAX2XMLReader extends Class { - SAX2XMLReader() { this.hasName("SAX2XMLReader") } +class Sax2XmlReader extends Class { + Sax2XmlReader() { this.hasName("SAX2XMLReader") } } /** @@ -120,7 +120,7 @@ class DisableDefaultEntityResolutionTranformer extends XXEFlowStateTranformer { call.getTarget() = f and ( f.getDeclaringType() instanceof AbstractDOMParserClass or - f.getDeclaringType() instanceof SAXParserClass + f.getDeclaringType() instanceof SaxParserClass ) and f.hasName("setDisableDefaultEntityResolution") and this = call.getQualifier() and @@ -195,7 +195,7 @@ class SetFeatureTranformer extends XXEFlowStateTranformer { SetFeatureTranformer() { exists(Call call, Function f | call.getTarget() = f and - f.getDeclaringType() instanceof SAX2XMLReader and + f.getDeclaringType() instanceof Sax2XmlReader and f.hasName("setFeature") and this = call.getQualifier() and globalValueNumber(call.getArgument(0)).getAnExpr().(VariableAccess).getTarget() instanceof @@ -225,8 +225,8 @@ class SetFeatureTranformer extends XXEFlowStateTranformer { class ParseFunction extends Function { ParseFunction() { this.getClassAndName("parse") instanceof AbstractDOMParserClass or - this.getClassAndName("parse") instanceof SAXParserClass or - this.getClassAndName("parse") instanceof SAX2XMLReader + this.getClassAndName("parse") instanceof SaxParserClass or + this.getClassAndName("parse") instanceof Sax2XmlReader } } @@ -245,10 +245,10 @@ class CreateLSParser extends Function { * The `createXMLReader` function that returns a newly created `SAX2XMLReader` * object. */ -class CreateXMLReader extends Function { - CreateXMLReader() { +class CreateXmlReader extends Function { + CreateXmlReader() { this.hasName("createXMLReader") and - this.getUnspecifiedType().(PointerType).getBaseType() instanceof SAX2XMLReader // returns a `SAX2XMLReader *`. + this.getUnspecifiedType().(PointerType).getBaseType() instanceof Sax2XmlReader // returns a `SAX2XMLReader *`. } } @@ -314,7 +314,7 @@ class XXEConfiguration extends DataFlow::Configuration { // source is the write on `this` of a call to the `SAXParser` // constructor. exists(CallInstruction call | - call.getStaticCallTarget() = any(SAXParserClass c).getAConstructor() and + call.getStaticCallTarget() = any(SaxParserClass c).getAConstructor() and node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() = call.getThisArgument() and encodeXercesFlowState(flowstate, 0, 1) // default configuration @@ -322,7 +322,7 @@ class XXEConfiguration extends DataFlow::Configuration { or // source is the result of a call to `createXMLReader`. exists(Call call | - call.getTarget() instanceof CreateXMLReader and + call.getTarget() instanceof CreateXmlReader and call = node.asExpr() and encodeXercesFlowState(flowstate, 0, 1) // default configuration ) From 85cc9b890160392a3b4b9a19dad87675fb6fc9e3 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 9 May 2022 13:00:29 +0100 Subject: [PATCH 149/171] C++: Use getClassAndName. --- cpp/ql/src/Security/CWE/CWE-611/XXE.ql | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql index 7daea2f1d63..c8b638ddecd 100644 --- a/cpp/ql/src/Security/CWE/CWE-611/XXE.ql +++ b/cpp/ql/src/Security/CWE/CWE-611/XXE.ql @@ -153,8 +153,7 @@ class CreateEntityReferenceNodesTranformer extends XXEFlowStateTranformer { CreateEntityReferenceNodesTranformer() { exists(Call call, Function f | call.getTarget() = f and - f.getDeclaringType() instanceof AbstractDOMParserClass and - f.hasName("setCreateEntityReferenceNodes") and + f.getClassAndName("setCreateEntityReferenceNodes") instanceof AbstractDOMParserClass and this = call.getQualifier() and newValue = call.getArgument(0) ) @@ -195,8 +194,7 @@ class SetFeatureTranformer extends XXEFlowStateTranformer { SetFeatureTranformer() { exists(Call call, Function f | call.getTarget() = f and - f.getDeclaringType() instanceof Sax2XmlReader and - f.hasName("setFeature") and + f.getClassAndName("setFeature") instanceof Sax2XmlReader and this = call.getQualifier() and globalValueNumber(call.getArgument(0)).getAnExpr().(VariableAccess).getTarget() instanceof FeatureDisableDefaultEntityResolution and From ab1252d1967b3a85d0b692241b53990bb12ce55f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 9 May 2022 14:19:40 +0200 Subject: [PATCH 150/171] Python: Add @precision high for `py/pam-auth-bypass` --- python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql b/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql index 595d1af13a4..7561dec7f67 100644 --- a/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql +++ b/python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql @@ -3,6 +3,7 @@ * @description Using only the `pam_authenticate` call to check the validity of a login can lead to a authorization bypass. * @kind problem * @problem.severity warning + * @precision high * @id py/pam-auth-bypass * @tags security * external/cwe/cwe-285 From 198c96982cab425773660c7f01370431f9cca6b8 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Mon, 9 May 2022 14:30:41 +0100 Subject: [PATCH 151/171] Add a comment to explain the unusual Action path --- .github/workflows/query-list.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/query-list.yml b/.github/workflows/query-list.yml index 6bd1d3a5bf3..952e5783e1c 100644 --- a/.github/workflows/query-list.yml +++ b/.github/workflows/query-list.yml @@ -30,6 +30,7 @@ jobs: with: python-version: 3.8 - name: Download CodeQL CLI + # Look under the `codeql` directory , as this is where we checked out the `github/codeql` repo uses: ./codeql/.github/actions/fetch-codeql - name: Unzip CodeQL CLI run: unzip -d codeql-cli codeql-linux64.zip From 71d1069a0a4a0b41fe5e39e65df2b72126da98df Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Mon, 9 May 2022 14:31:05 +0100 Subject: [PATCH 152/171] Fix typo --- .github/workflows/query-list.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/query-list.yml b/.github/workflows/query-list.yml index 952e5783e1c..f8f2d451adb 100644 --- a/.github/workflows/query-list.yml +++ b/.github/workflows/query-list.yml @@ -30,7 +30,7 @@ jobs: with: python-version: 3.8 - name: Download CodeQL CLI - # Look under the `codeql` directory , as this is where we checked out the `github/codeql` repo + # Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo uses: ./codeql/.github/actions/fetch-codeql - name: Unzip CodeQL CLI run: unzip -d codeql-cli codeql-linux64.zip From 4a6789182d4d4d18526e05d05cf3028c3a59b92c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 9 May 2022 16:37:12 +0200 Subject: [PATCH 153/171] Python: Apply suggestions from code review Co-authored-by: yoff --- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index e67e90cc794..ef60841acd6 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -3265,14 +3265,7 @@ private module StdlibPrivate { API::moduleImport("xml") .getMember("etree") .getMember("ElementTree") - .getMember("XMLParser") - .getACall() - or - this = - API::moduleImport("xml") - .getMember("etree") - .getMember("ElementTree") - .getMember("XMLPullParser") + .getMember(["XMLParser", "XMLPullParser"]) .getACall() } } From bf0e32ae829372c377ec6f5083e210ead1e77bf3 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 9 May 2022 14:12:32 +0000 Subject: [PATCH 154/171] C#: Port the existing compiler-tracing.spec files to Lua. --- csharp/tools/tracing-config.lua | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 csharp/tools/tracing-config.lua diff --git a/csharp/tools/tracing-config.lua b/csharp/tools/tracing-config.lua new file mode 100644 index 00000000000..e7d1ce65dfd --- /dev/null +++ b/csharp/tools/tracing-config.lua @@ -0,0 +1,55 @@ +function RegisterExtractorPack() + local extractor = GetPlatformToolsDirectory() .. + 'Semmle.Extraction.CSharp.Driver' + if OperatingSystem == 'windows' then + extractor = GetPlatformToolsDirectory() .. + 'Semmle.Extraction.CSharp.Driver.exe' + end + local windowsMatchers = { + CreatePatternMatcher({'^dotnet%.exe$'}, MatchCompilerName, extractor, + {prepend = {'--dotnetexec', '--cil'}}), + CreatePatternMatcher({'^csc.*%.exe$'}, MatchCompilerName, extractor, { + prepend = {'--compiler', '"${compiler}"', '--cil'} + }), + CreatePatternMatcher({'^fakes.*%.exe$', 'moles.*%.exe'}, + MatchCompilerName, nil, {trace = false}) + } + local posixMatchers = { + CreatePatternMatcher({'^mcs%.exe$', '^csc%.exe$'}, MatchCompilerName, + extractor, { + prepend = {'--compiler', '"${compiler}"', '--cil'} + }), + CreatePatternMatcher({'^mono', '^dotnet$'}, MatchCompilerName, + extractor, {prepend = {'--dotnetexec', '--cil'}}), + function(compilerName, compilerPath, compilerArguments, _languageId) + if MatchCompilerName('^msbuild$', compilerName, compilerPath, + compilerArguments) or + MatchCompilerName('^xbuild$', compilerName, compilerPath, + compilerArguments) then + return { + replace = true, + invocations = { + { + path = compilerPath, + transformedArguments = { + nativeArgumentPointer = compilerArguments['nativeArgumentPointer'], + append = {'/p:UseSharedCompilation=false'}, + prepend = {} + } + } + } + } + end + end + } + if OperatingSystem == 'windows' then + return windowsMatchers + else + return posixMatchers + end + +end + +-- Return a list of minimum supported versions of the configuration file format +-- return one entry per supported major version. +function GetCompatibleVersions() return {'1.0.0'} end From 2a5908ff49fef44410fb9a2c74a2eec3ddc6ea0d Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 9 May 2022 17:08:49 +0200 Subject: [PATCH 155/171] python: require all settings be vulnerable at least all thos not in tests --- .../CWE-352/CSRFProtectionDisabled.ql | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql index 24917411fb4..f85cf319572 100644 --- a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql @@ -14,12 +14,24 @@ import python import semmle.python.Concepts -from HTTP::Server::CsrfProtectionSetting s -where - s.getVerificationSetting() = false and - not exists(HTTP::Server::CsrfLocalProtectionSetting p | p.csrfEnabled()) and +predicate relevantSetting(HTTP::Server::CsrfProtectionSetting s) { // rule out test code as this is a common place to turn off CSRF protection. // We don't use normal `TestScope` to find test files, since we also want to match // a settings file such as `.../integration-tests/settings.py` not s.getLocation().getFile().getAbsolutePath().matches("%test%") -select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened." +} + +predicate vulnerableSetting(HTTP::Server::CsrfProtectionSetting s) { + s.getVerificationSetting() = false and + not exists(HTTP::Server::CsrfLocalProtectionSetting p | p.csrfEnabled()) and + relevantSetting(s) +} + +from HTTP::Server::CsrfProtectionSetting setting +where + vulnerableSetting(setting) and + // We have seen examples of dummy projects with vulnerable settings alongside a main + // project with a protecting settings file. We want to rule out this scenario, so we + // require all non-test settings to be vulnerable. + forall( HTTP::Server::CsrfProtectionSetting s| relevantSetting(s) | vulnerableSetting(s) ) +select setting, "Potential CSRF vulnerability due to forgery protection being disabled or weakened." From c08e6fdc1ed904c8cabf809c1d581f2e490df4c4 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Mon, 9 May 2022 17:50:49 +0200 Subject: [PATCH 156/171] Swift codegen: add predicate properties Properties marked with `predicate` in the schema are now accepted. * in the dbscheme, they will translate to a table with a single `id` column (and the table name will not be pluralized) * in C++ classes, they will translate to `bool` fields * in QL classes, they will translate to predicates Closes https://github.com/github/codeql-c-team/issues/1016 --- swift/codegen/cppgen.py | 8 ++- swift/codegen/dbschemegen.py | 9 +++ swift/codegen/lib/cpp.py | 3 +- swift/codegen/lib/ql.py | 28 +++++---- swift/codegen/lib/schema.py | 22 ++++--- swift/codegen/qlgen.py | 8 +++ swift/codegen/schema.yml | 1 + swift/codegen/templates/cpp_classes.mustache | 3 + swift/codegen/templates/ql_class.mustache | 8 +-- swift/codegen/test/test_cpp.py | 15 ++--- swift/codegen/test/test_cppgen.py | 11 ++++ swift/codegen/test/test_dbschemegen.py | 35 +++++++++++ swift/codegen/test/test_ql.py | 63 +++++++++++-------- swift/codegen/test/test_qlgen.py | 16 ++++- swift/codegen/test/test_schema.py | 2 + .../swift/generated/type/AnyFunctionType.qll | 2 + swift/ql/lib/swift.dbscheme | 5 ++ 17 files changed, 179 insertions(+), 60 deletions(-) diff --git a/swift/codegen/cppgen.py b/swift/codegen/cppgen.py index f45512512aa..eee66a812f0 100644 --- a/swift/codegen/cppgen.py +++ b/swift/codegen/cppgen.py @@ -8,6 +8,9 @@ from swift.codegen.lib import cpp, generator, schema def _get_type(t: str, trap_affix: str) -> str: + if t is None: + # this is a predicate + return "bool" if t == "string": return "std::string" if t == "boolean": @@ -20,12 +23,15 @@ def _get_type(t: str, trap_affix: str) -> str: def _get_field(cls: schema.Class, p: schema.Property, trap_affix: str) -> cpp.Field: trap_name = None if not p.is_single: - trap_name = inflection.pluralize(inflection.camelize(f"{cls.name}_{p.name}")) + trap_name = inflection.camelize(f"{cls.name}_{p.name}") + if not p.is_predicate: + trap_name = inflection.pluralize(trap_name) args = dict( name=p.name + ("_" if p.name in cpp.cpp_keywords else ""), type=_get_type(p.type, trap_affix), is_optional=p.is_optional, is_repeated=p.is_repeated, + is_predicate=p.is_predicate, trap_name=trap_name, ) args.update(cpp.get_field_override(p.name)) diff --git a/swift/codegen/dbschemegen.py b/swift/codegen/dbschemegen.py index efe45c0b997..c95316e5499 100755 --- a/swift/codegen/dbschemegen.py +++ b/swift/codegen/dbschemegen.py @@ -57,6 +57,15 @@ def cls_to_dbscheme(cls: schema.Class): Column(f.name, dbtype(f.type)), ], ) + elif f.is_predicate: + yield Table( + keyset=KeySet(["id"]), + name=inflection.underscore(f"{cls.name}_{f.name}"), + columns=[ + Column("id", type=dbtype(cls.name)), + ], + ) + def get_declarations(data: schema.Schema): diff --git a/swift/codegen/lib/cpp.py b/swift/codegen/lib/cpp.py index 886ef8069e6..82dfbb44bcb 100644 --- a/swift/codegen/lib/cpp.py +++ b/swift/codegen/lib/cpp.py @@ -35,6 +35,7 @@ class Field: type: str is_optional: bool = False is_repeated: bool = False + is_predicate: bool = False trap_name: str = None first: bool = False @@ -61,7 +62,7 @@ class Field: @property def is_single(self): - return not (self.is_optional or self.is_repeated) + return not (self.is_optional or self.is_repeated or self.is_predicate) diff --git a/swift/codegen/lib/ql.py b/swift/codegen/lib/ql.py index ee9103fd990..5d4a7076414 100644 --- a/swift/codegen/lib/ql.py +++ b/swift/codegen/lib/ql.py @@ -14,29 +14,35 @@ class Param: @dataclass class Property: singular: str - type: str - tablename: str - tableparams: List[Param] + type: str = None + tablename: str = None + tableparams: List[Param] = field(default_factory=list) plural: str = None first: bool = False local_var: str = "x" is_optional: bool = False + is_predicate: bool = False def __post_init__(self): - assert self.tableparams - if self.type_is_class: - self.tableparams = [x if x != "result" else self.local_var for x in self.tableparams] - self.tableparams = [Param(x) for x in self.tableparams] - self.tableparams[0].first = True + if self.tableparams: + if self.type_is_class: + self.tableparams = [x if x != "result" else self.local_var for x in self.tableparams] + self.tableparams = [Param(x) for x in self.tableparams] + self.tableparams[0].first = True @property - def indefinite_article(self): + def getter(self): + return f"get{self.singular}" if not self.is_predicate else self.singular + + @property + def indefinite_getter(self): if self.plural: - return "An" if self.singular[0] in "AEIO" else "A" + article = "An" if self.singular[0] in "AEIO" else "A" + return f"get{article}{self.singular}" @property def type_is_class(self): - return self.type[0].isupper() + return bool(self.type) and self.type[0].isupper() @property def is_repeated(self): diff --git a/swift/codegen/lib/schema.py b/swift/codegen/lib/schema.py index 06ceb4b63bb..a65aaf24dca 100644 --- a/swift/codegen/lib/schema.py +++ b/swift/codegen/lib/schema.py @@ -15,9 +15,10 @@ class Property: is_single: ClassVar = False is_optional: ClassVar = False is_repeated: ClassVar = False + is_predicate: ClassVar = False name: str - type: str + type: str = None @dataclass @@ -41,6 +42,11 @@ class RepeatedOptionalProperty(Property): is_repeated: ClassVar = True +@dataclass +class PredicateProperty(Property): + is_predicate: ClassVar = True + + @dataclass class Class: name: str @@ -58,17 +64,15 @@ class Schema: def _parse_property(name, type): if type.endswith("?*"): - cls = RepeatedOptionalProperty - type = type[:-2] + return RepeatedOptionalProperty(name, type[:-2]) elif type.endswith("*"): - cls = RepeatedProperty - type = type[:-1] + return RepeatedProperty(name, type[:-1]) elif type.endswith("?"): - cls = OptionalProperty - type = type[:-1] + return OptionalProperty(name, type[:-1]) + elif type == "predicate": + return PredicateProperty(name) else: - cls = SingleProperty - return cls(name, type) + return SingleProperty(name, type) class _DirSelector: diff --git a/swift/codegen/qlgen.py b/swift/codegen/qlgen.py index 5d08f5a0410..4eea533904a 100755 --- a/swift/codegen/qlgen.py +++ b/swift/codegen/qlgen.py @@ -36,6 +36,14 @@ def get_ql_property(cls: schema.Class, prop: schema.Property): tableparams=["this", "result"], is_optional=True, ) + elif prop.is_predicate: + return ql.Property( + singular=inflection.camelize(prop.name, uppercase_first_letter=False), + type="predicate", + tablename=inflection.underscore(f"{cls.name}_{prop.name}"), + tableparams=["this"], + is_predicate=True, + ) def get_ql_class(cls: schema.Class): diff --git a/swift/codegen/schema.yml b/swift/codegen/schema.yml index 4ea4a8190a6..46e0b508ae5 100644 --- a/swift/codegen/schema.yml +++ b/swift/codegen/schema.yml @@ -59,6 +59,7 @@ AnyFunctionType: result: Type param_types: Type* param_labels: string* + is_throwing: predicate AnyGenericType: _extends: Type diff --git a/swift/codegen/templates/cpp_classes.mustache b/swift/codegen/templates/cpp_classes.mustache index 3e9d12084c9..15e33a378dc 100644 --- a/swift/codegen/templates/cpp_classes.mustache +++ b/swift/codegen/templates/cpp_classes.mustache @@ -33,6 +33,9 @@ struct {{name}}{{#final}} : Binding<{{name}}Tag>{{#bases}}, {{ref.name}}{{/bases {{ref.name}}::emit(id, out); {{/bases}} {{#fields}} + {{#is_predicate}} + if ({{name}}) out << {{trap_name}}{{trap_affix}}{id} << '\n'; + {{/is_predicate}} {{#is_optional}} {{^is_repeated}} if ({{name}}) out << {{trap_name}}{{trap_affix}}{id, *{{name}}} << '\n'; diff --git a/swift/codegen/templates/ql_class.mustache b/swift/codegen/templates/ql_class.mustache index 12ca76c9975..89da396be90 100644 --- a/swift/codegen/templates/ql_class.mustache +++ b/swift/codegen/templates/ql_class.mustache @@ -21,7 +21,7 @@ class {{name}}Base extends {{db_id}}{{#bases}}, {{.}}{{/bases}} { {{/final}} {{#properties}} - {{type}} get{{singular}}({{#is_repeated}}int index{{/is_repeated}}) { + {{type}} {{getter}}({{#is_repeated}}int index{{/is_repeated}}) { {{#type_is_class}} exists({{type}} {{local_var}} | {{tablename}}({{#tableparams}}{{^first}}, {{/first}}{{param}}{{/tableparams}}) @@ -34,13 +34,13 @@ class {{name}}Base extends {{db_id}}{{#bases}}, {{.}}{{/bases}} { } {{#is_repeated}} - {{type}} get{{indefinite_article}}{{singular}}() { - result = get{{singular}}(_) + {{type}} {{indefinite_getter}}() { + result = {{getter}}(_) } {{^is_optional}} int getNumberOf{{plural}}() { - result = count(get{{indefinite_article}}{{singular}}()) + result = count({{indefinite_getter}}()) } {{/is_optional}} {{/is_repeated}} diff --git a/swift/codegen/test/test_cpp.py b/swift/codegen/test/test_cpp.py index 74dbc2d2182..06ff50f8a51 100644 --- a/swift/codegen/test/test_cpp.py +++ b/swift/codegen/test/test_cpp.py @@ -27,14 +27,15 @@ def test_field_get_streamer(type, expected): assert f.get_streamer()("value") == expected -@pytest.mark.parametrize("is_optional,is_repeated,expected", [ - (False, False, True), - (True, False, False), - (False, True, False), - (True, True, False), +@pytest.mark.parametrize("is_optional,is_repeated,is_predicate,expected", [ + (False, False, False, True), + (True, False, False, False), + (False, True, False, False), + (True, True, False, False), + (False, False, True, False), ]) -def test_field_is_single(is_optional, is_repeated, expected): - f = cpp.Field("name", "type", is_optional=is_optional, is_repeated=is_repeated) +def test_field_is_single(is_optional, is_repeated, is_predicate, expected): + f = cpp.Field("name", "type", is_optional=is_optional, is_repeated=is_repeated, is_predicate=is_predicate) assert f.is_single is expected diff --git a/swift/codegen/test/test_cppgen.py b/swift/codegen/test/test_cppgen.py index ac37b7300c5..b4e766af9dc 100644 --- a/swift/codegen/test/test_cppgen.py +++ b/swift/codegen/test/test_cppgen.py @@ -92,6 +92,17 @@ def test_class_with_field(generate, type, expected, property_cls, optional, repe ] +def test_class_with_predicate(generate): + assert generate([ + schema.Class(name="MyClass", properties=[schema.PredicateProperty("prop")]), + ]) == [ + cpp.Class(name="MyClass", + fields=[cpp.Field("prop", "bool", trap_name="MyClassProp", is_predicate=True)], + trap_name="MyClasses", + final=True) + ] + + @pytest.mark.parametrize("name", ["start_line", "start_column", "end_line", "end_column", "index", "num_whatever", "width"]) def test_class_with_overridden_unsigned_field(generate, name): diff --git a/swift/codegen/test/test_dbschemegen.py b/swift/codegen/test/test_dbschemegen.py index 82521fb9892..54f1e1796f7 100644 --- a/swift/codegen/test/test_dbschemegen.py +++ b/swift/codegen/test/test_dbschemegen.py @@ -156,6 +156,33 @@ def test_final_class_with_repeated_field(opts, input, renderer, property_cls): ) +def test_final_class_with_predicate_field(opts, input, renderer): + input.classes = [ + schema.Class("Object", properties=[ + schema.PredicateProperty("foo"), + ]), + ] + assert generate(opts, renderer) == dbscheme.Scheme( + src=schema_file, + includes=[], + declarations=[ + dbscheme.Table( + name="objects", + columns=[ + dbscheme.Column('id', '@object', binding=True), + ] + ), + dbscheme.Table( + name="object_foo", + keyset=dbscheme.KeySet(["id"]), + columns=[ + dbscheme.Column('id', '@object'), + ] + ), + ], + ) + + def test_final_class_with_more_fields(opts, input, renderer): input.classes = [ schema.Class("Object", properties=[ @@ -164,6 +191,7 @@ def test_final_class_with_more_fields(opts, input, renderer): schema.OptionalProperty("three", "z"), schema.RepeatedProperty("four", "u"), schema.RepeatedOptionalProperty("five", "v"), + schema.PredicateProperty("six"), ]), ] assert generate(opts, renderer) == dbscheme.Scheme( @@ -204,6 +232,13 @@ def test_final_class_with_more_fields(opts, input, renderer): dbscheme.Column('five', 'v'), ] ), + dbscheme.Table( + name="object_six", + keyset=dbscheme.KeySet(["id"]), + columns=[ + dbscheme.Column('id', '@object'), + ] + ), ], ) diff --git a/swift/codegen/test/test_ql.py b/swift/codegen/test/test_ql.py index e87383695c6..caa513c1b15 100644 --- a/swift/codegen/test/test_ql.py +++ b/swift/codegen/test/test_ql.py @@ -12,31 +12,32 @@ def test_property_has_first_table_param_marked(): assert [p.param for p in prop.tableparams] == tableparams -def test_property_not_a_class(): - tableparams = ["x", "result", "y"] - prop = ql.Property("Prop", "foo", "props", tableparams) - assert not prop.type_is_class - assert [p.param for p in prop.tableparams] == tableparams - - -def test_property_is_a_class(): - tableparams = ["x", "result", "y"] - prop = ql.Property("Prop", "Foo", "props", tableparams) - assert prop.type_is_class - assert [p.param for p in prop.tableparams] == ["x", prop.local_var, "y"] - - -@pytest.mark.parametrize("name,expected_article", [ - ("Argument", "An"), - ("Element", "An"), - ("Integer", "An"), - ("Operator", "An"), - ("Unit", "A"), - ("Whatever", "A"), +@pytest.mark.parametrize("type,expected", [ + ("Foo", True), + ("Bar", True), + ("foo", False), + ("bar", False), + (None, False), ]) -def test_property_indefinite_article(name, expected_article): - prop = ql.Property(name, "Foo", "props", ["x"], plural="X") - assert prop.indefinite_article == expected_article +def test_property_is_a_class(type, expected): + tableparams = ["a", "result", "b"] + expected_tableparams = ["a", "x" if expected else "result", "b"] + prop = ql.Property("Prop", type, tableparams=tableparams) + assert prop.type_is_class is expected + assert [p.param for p in prop.tableparams] == expected_tableparams + + +@pytest.mark.parametrize("name,expected_getter", [ + ("Argument", "getAnArgument"), + ("Element", "getAnElement"), + ("Integer", "getAnInteger"), + ("Operator", "getAnOperator"), + ("Unit", "getAUnit"), + ("Whatever", "getAWhatever"), +]) +def test_property_indefinite_article(name, expected_getter): + prop = ql.Property(name, plural="X") + assert prop.indefinite_getter == expected_getter @pytest.mark.parametrize("plural,expected", [ @@ -49,9 +50,19 @@ def test_property_is_plural(plural, expected): assert prop.is_repeated is expected -def test_property_no_plural_no_indefinite_article(): +def test_property_no_plural_no_indefinite_getter(): prop = ql.Property("Prop", "Foo", "props", ["x"]) - assert prop.indefinite_article is None + assert prop.indefinite_getter is None + + +def test_property_getter(): + prop = ql.Property("Prop", "Foo") + assert prop.getter == "getProp" + + +def test_property_predicate_getter(): + prop = ql.Property("prop", is_predicate=True) + assert prop.getter == "prop" def test_class_sorts_bases(): diff --git a/swift/codegen/test/test_qlgen.py b/swift/codegen/test/test_qlgen.py index d273539e375..e5405406747 100644 --- a/swift/codegen/test/test_qlgen.py +++ b/swift/codegen/test/test_qlgen.py @@ -2,7 +2,7 @@ import subprocess import sys from swift.codegen import qlgen -from swift.codegen.lib import ql, paths +from swift.codegen.lib import ql from swift.codegen.test.utils import * @@ -141,6 +141,20 @@ def test_repeated_optional_property(opts, input, renderer): } +def test_predicate_property(opts, input, renderer): + input.classes = [ + schema.Class("MyObject", properties=[schema.PredicateProperty("is_foo")]), + ] + assert generate(opts, renderer) == { + import_file(): ql.ImportList([stub_import_prefix + "MyObject"]), + stub_path() / "MyObject.qll": ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + ql_output_path() / "MyObject.qll": ql.Class(name="MyObject", final=True, properties=[ + ql.Property(singular="isFoo", type="predicate", tablename="my_object_is_foo", tableparams=["this"], + is_predicate=True), + ]) + } + + def test_single_class_property(opts, input, renderer): input.classes = [ schema.Class("MyObject", properties=[schema.SingleProperty("foo", "Bar")]), diff --git a/swift/codegen/test/test_schema.py b/swift/codegen/test/test_schema.py index 36367a76b1f..c1b64648894 100644 --- a/swift/codegen/test/test_schema.py +++ b/swift/codegen/test/test_schema.py @@ -141,6 +141,7 @@ A: two: int? three: bool* four: x?* + five: predicate """) assert ret.classes == [ schema.Class(root_name, derived={'A'}), @@ -149,6 +150,7 @@ A: schema.OptionalProperty('two', 'int'), schema.RepeatedProperty('three', 'bool'), schema.RepeatedOptionalProperty('four', 'x'), + schema.PredicateProperty('five'), ]), ] diff --git a/swift/ql/lib/codeql/swift/generated/type/AnyFunctionType.qll b/swift/ql/lib/codeql/swift/generated/type/AnyFunctionType.qll index 847017e44f2..6add8032bc1 100644 --- a/swift/ql/lib/codeql/swift/generated/type/AnyFunctionType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/AnyFunctionType.qll @@ -25,4 +25,6 @@ class AnyFunctionTypeBase extends @any_function_type, Type { string getAParamLabel() { result = getParamLabel(_) } int getNumberOfParamLabels() { result = count(getAParamLabel()) } + + predicate isThrowing() { any_function_type_is_throwing(this) } } diff --git a/swift/ql/lib/swift.dbscheme b/swift/ql/lib/swift.dbscheme index fbff22210bf..8d3ab41cf22 100644 --- a/swift/ql/lib/swift.dbscheme +++ b/swift/ql/lib/swift.dbscheme @@ -167,6 +167,11 @@ any_function_type_param_labels( string param_label: string ref ); +#keyset[id] +any_function_type_is_throwing( + int id: @any_function_type ref +); + @any_generic_type = @nominal_or_bound_generic_nominal_type | @unbound_generic_type From e80ee46fe41078bd82694efaffd23dd0c19413ba Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 9 May 2022 14:03:45 +0200 Subject: [PATCH 157/171] add model for the cash library --- javascript/ql/lib/change-notes/2022-05-09-cash.md | 5 +++++ .../lib/semmle/javascript/frameworks/jQuery.qll | 8 ++++---- .../CWE-079/XssThroughDom/XssThroughDom.expected | 15 +++++++++++++++ .../CWE-079/XssThroughDom/xss-through-dom.js | 8 ++++++++ 4 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 javascript/ql/lib/change-notes/2022-05-09-cash.md diff --git a/javascript/ql/lib/change-notes/2022-05-09-cash.md b/javascript/ql/lib/change-notes/2022-05-09-cash.md new file mode 100644 index 00000000000..e5e0056e86c --- /dev/null +++ b/javascript/ql/lib/change-notes/2022-05-09-cash.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* The [cash](https://github.com/fabiospampinato/cash) library is now modelled as an alias for JQuery. + Sinks and sources from cash should now be handled by all XSS queries. \ No newline at end of file diff --git a/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll b/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll index 28a01dba7ab..31d1d5b99d2 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll @@ -406,11 +406,11 @@ module JQuery { private class DefaultRange extends Range { DefaultRange() { - // either a reference to a global variable `$` or `jQuery` - this = DataFlow::globalVarRef(any(string jq | jq = "$" or jq = "jQuery")) + // either a reference to a global variable `$`, `jQuery`, or `cash` + this = DataFlow::globalVarRef(["$", "jQuery", "cash"]) or - // or imported from a module named `jquery` or `zepto` - this = DataFlow::moduleImport(["jquery", "zepto"]) + // or imported from a module named `jquery`, `zepto`, or `cash-dom` + this = DataFlow::moduleImport(["jquery", "zepto", "cash-dom"]) or this.hasUnderlyingType("JQueryStatic") } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected index cc1988e5adf..57c6899d078 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected @@ -150,6 +150,13 @@ nodes | xss-through-dom.js:131:19:131:26 | linkText | | xss-through-dom.js:132:16:132:23 | linkText | | xss-through-dom.js:132:16:132:23 | linkText | +| xss-through-dom.js:139:11:139:52 | src | +| xss-through-dom.js:139:17:139:52 | documen ... k").src | +| xss-through-dom.js:139:17:139:52 | documen ... k").src | +| xss-through-dom.js:140:19:140:21 | src | +| xss-through-dom.js:140:19:140:21 | src | +| xss-through-dom.js:141:25:141:27 | src | +| xss-through-dom.js:141:25:141:27 | src | edges | forms.js:8:23:8:28 | values | forms.js:9:31:9:36 | values | | forms.js:8:23:8:28 | values | forms.js:9:31:9:36 | values | @@ -246,6 +253,12 @@ edges | xss-through-dom.js:130:17:130:68 | wSelect ... ) \|\| '' | xss-through-dom.js:130:6:130:68 | linkText | | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | xss-through-dom.js:130:17:130:62 | wSelect ... tring() | | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | xss-through-dom.js:130:17:130:62 | wSelect ... tring() | +| xss-through-dom.js:139:11:139:52 | src | xss-through-dom.js:140:19:140:21 | src | +| xss-through-dom.js:139:11:139:52 | src | xss-through-dom.js:140:19:140:21 | src | +| xss-through-dom.js:139:11:139:52 | src | xss-through-dom.js:141:25:141:27 | src | +| xss-through-dom.js:139:11:139:52 | src | xss-through-dom.js:141:25:141:27 | src | +| xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:139:11:139:52 | src | +| xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:139:11:139:52 | src | #select | forms.js:9:31:9:40 | values.foo | forms.js:8:23:8:28 | values | forms.js:9:31:9:40 | values.foo | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:8:23:8:28 | values | DOM text | | forms.js:12:31:12:40 | values.bar | forms.js:11:24:11:29 | values | forms.js:12:31:12:40 | values.bar | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:11:24:11:29 | values | DOM text | @@ -287,3 +300,5 @@ edges | xss-through-dom.js:131:19:131:26 | linkText | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | xss-through-dom.js:131:19:131:26 | linkText | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | DOM text | | xss-through-dom.js:132:16:132:23 | linkText | xss-through-dom.js:130:17:130:37 | wSelect ... tring() | xss-through-dom.js:132:16:132:23 | linkText | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:130:17:130:37 | wSelect ... tring() | DOM text | | xss-through-dom.js:132:16:132:23 | linkText | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | xss-through-dom.js:132:16:132:23 | linkText | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | DOM text | +| xss-through-dom.js:140:19:140:21 | src | xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:140:19:140:21 | src | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:139:17:139:52 | documen ... k").src | DOM text | +| xss-through-dom.js:141:25:141:27 | src | xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:141:25:141:27 | src | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:139:17:139:52 | documen ... k").src | DOM text | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/xss-through-dom.js b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/xss-through-dom.js index 8e89affa0a9..7728722bd16 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/xss-through-dom.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/xss-through-dom.js @@ -131,4 +131,12 @@ class Sub extends Super { elem.innerHTML = linkText; // NOT OK $("#id").html(linkText); // NOT OK elem.innerText = linkText; // OK +})(); + +const cashDom = require("cash-dom"); + +(function () { + const src = document.getElementById("#link").src; + cash("#id").html(src); // NOT OK. + cashDom("#id").html(src); // NOT OK })(); \ No newline at end of file From 1c7e53314433fb2bde163587cff9106c50691d9a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 9 May 2022 21:22:27 +0200 Subject: [PATCH 158/171] python: format --- python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql index f85cf319572..36a4e315ffc 100644 --- a/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql +++ b/python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql @@ -33,5 +33,5 @@ where // We have seen examples of dummy projects with vulnerable settings alongside a main // project with a protecting settings file. We want to rule out this scenario, so we // require all non-test settings to be vulnerable. - forall( HTTP::Server::CsrfProtectionSetting s| relevantSetting(s) | vulnerableSetting(s) ) + forall(HTTP::Server::CsrfProtectionSetting s | relevantSetting(s) | vulnerableSetting(s)) select setting, "Potential CSRF vulnerability due to forgery protection being disabled or weakened." From 40503aa368b7d1414e13cb1256af0649967244f4 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 10 May 2022 08:06:25 +0000 Subject: [PATCH 159/171] Address review. --- csharp/tools/tracing-config.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/csharp/tools/tracing-config.lua b/csharp/tools/tracing-config.lua index e7d1ce65dfd..77d69beb6b1 100644 --- a/csharp/tools/tracing-config.lua +++ b/csharp/tools/tracing-config.lua @@ -1,10 +1,7 @@ function RegisterExtractorPack() local extractor = GetPlatformToolsDirectory() .. 'Semmle.Extraction.CSharp.Driver' - if OperatingSystem == 'windows' then - extractor = GetPlatformToolsDirectory() .. - 'Semmle.Extraction.CSharp.Driver.exe' - end + if OperatingSystem == 'windows' then extractor = extractor .. '.exe' end local windowsMatchers = { CreatePatternMatcher({'^dotnet%.exe$'}, MatchCompilerName, extractor, {prepend = {'--dotnetexec', '--cil'}}), From aa3d7babf42f88aa66b2f5601203ca21df7c4673 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 10 May 2022 11:37:41 +0200 Subject: [PATCH 160/171] python: fix bad merge caused by an optimistic attempt at solving a merge conflict in the online GUI. --- python/ql/test/experimental/meta/ConceptsTest.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index de0433bee63..8b1a6bad2bb 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -570,6 +570,9 @@ class CsrfLocalProtectionSettingTest extends InlineExpectationsTest { if p.csrfEnabled() then tag = "CsrfLocalProtectionEnabled" else tag = "CsrfLocalProtectionDisabled" + ) + } +} class XmlParsingTest extends InlineExpectationsTest { XmlParsingTest() { this = "XmlParsingTest" } From 0b9dc9703f008c1678d8d5c5167a4fb99d50abd2 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Tue, 10 May 2022 11:54:39 +0200 Subject: [PATCH 161/171] Swift: changes required for TBD node rework These changes are required to allow a new type-safe approach to TBD nodes, that will come in a separate commit. This introduces: * the possibility to add properties to the root `Element` * a functor taking tags to the corresponding binding trap entry * `hasProp()` methods for optional properties in QL * `getPrimaryQlClass()` method --- swift/codegen/cppgen.py | 2 +- swift/codegen/lib/cpp.py | 14 ++++---------- swift/codegen/lib/schema.py | 3 +-- swift/codegen/templates/cpp_classes.mustache | 14 +++++++------- swift/codegen/templates/ql_class.mustache | 10 +++++++++- swift/codegen/templates/trap_traps.mustache | 15 +++++++++++---- swift/codegen/test/test_cpp.py | 8 ++++---- swift/codegen/test/test_schema.py | 12 ++++++++++++ swift/codegen/trapgen.py | 2 +- swift/extractor/trap/TrapLabel.h | 4 +++- swift/extractor/trap/TrapTagTraits.h | 10 ++++++++-- swift/ql/lib/codeql/swift/generated/Element.qll | 2 ++ swift/ql/lib/codeql/swift/generated/File.qll | 2 +- swift/ql/lib/codeql/swift/generated/Location.qll | 2 +- .../lib/codeql/swift/generated/UnknownAstNode.qll | 2 +- .../swift/generated/decl/AbstractFunctionDecl.qll | 2 ++ .../codeql/swift/generated/decl/AccessorDecl.qll | 2 +- .../swift/generated/decl/AssociatedTypeDecl.qll | 2 +- .../lib/codeql/swift/generated/decl/ClassDecl.qll | 2 +- .../swift/generated/decl/ConcreteFuncDecl.qll | 2 +- .../swift/generated/decl/ConcreteVarDecl.qll | 2 +- .../swift/generated/decl/ConstructorDecl.qll | 2 +- .../swift/generated/decl/DestructorDecl.qll | 2 +- .../codeql/swift/generated/decl/EnumCaseDecl.qll | 2 +- .../lib/codeql/swift/generated/decl/EnumDecl.qll | 2 +- .../swift/generated/decl/EnumElementDecl.qll | 2 +- .../codeql/swift/generated/decl/ExtensionDecl.qll | 2 +- .../swift/generated/decl/GenericTypeParamDecl.qll | 2 +- .../codeql/swift/generated/decl/IfConfigDecl.qll | 2 +- .../codeql/swift/generated/decl/ImportDecl.qll | 2 +- .../swift/generated/decl/InfixOperatorDecl.qll | 2 +- .../swift/generated/decl/MissingMemberDecl.qll | 2 +- .../codeql/swift/generated/decl/ModuleDecl.qll | 2 +- .../swift/generated/decl/OpaqueTypeDecl.qll | 2 +- .../lib/codeql/swift/generated/decl/ParamDecl.qll | 2 +- .../swift/generated/decl/PatternBindingDecl.qll | 4 +++- .../swift/generated/decl/PostfixOperatorDecl.qll | 2 +- .../swift/generated/decl/PoundDiagnosticDecl.qll | 2 +- .../swift/generated/decl/PrecedenceGroupDecl.qll | 2 +- .../swift/generated/decl/PrefixOperatorDecl.qll | 2 +- .../codeql/swift/generated/decl/ProtocolDecl.qll | 2 +- .../codeql/swift/generated/decl/StructDecl.qll | 2 +- .../codeql/swift/generated/decl/SubscriptDecl.qll | 2 +- .../swift/generated/decl/TopLevelCodeDecl.qll | 2 +- .../codeql/swift/generated/decl/TypeAliasDecl.qll | 2 +- .../generated/expr/AnyHashableErasureExpr.qll | 2 +- .../generated/expr/AppliedPropertyWrapperExpr.qll | 2 +- .../swift/generated/expr/ArchetypeToSuperExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/Argument.qll | 2 +- .../lib/codeql/swift/generated/expr/ArrayExpr.qll | 2 +- .../swift/generated/expr/ArrayToPointerExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/ArrowExpr.qll | 2 +- .../codeql/swift/generated/expr/AssignExpr.qll | 2 +- .../swift/generated/expr/AutoClosureExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/AwaitExpr.qll | 2 +- .../codeql/swift/generated/expr/BinaryExpr.qll | 2 +- .../swift/generated/expr/BindOptionalExpr.qll | 2 +- .../swift/generated/expr/BooleanLiteralExpr.qll | 2 +- .../swift/generated/expr/BridgeFromObjCExpr.qll | 2 +- .../swift/generated/expr/BridgeToObjCExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/CallExpr.qll | 2 +- .../swift/generated/expr/CaptureListExpr.qll | 2 +- .../generated/expr/ClassMetatypeToObjectExpr.qll | 2 +- .../codeql/swift/generated/expr/ClosureExpr.qll | 2 +- .../swift/generated/expr/CodeCompletionExpr.qll | 2 +- .../codeql/swift/generated/expr/CoerceExpr.qll | 2 +- .../expr/CollectionUpcastConversionExpr.qll | 2 +- .../expr/ConditionalBridgeFromObjCExpr.qll | 2 +- .../generated/expr/ConditionalCheckedCastExpr.qll | 2 +- .../generated/expr/ConstructorRefCallExpr.qll | 2 +- .../expr/CovariantFunctionConversionExpr.qll | 2 +- .../expr/CovariantReturnConversionExpr.qll | 2 +- .../codeql/swift/generated/expr/DeclRefExpr.qll | 2 +- .../swift/generated/expr/DefaultArgumentExpr.qll | 4 +++- .../swift/generated/expr/DerivedToBaseExpr.qll | 2 +- .../swift/generated/expr/DestructureTupleExpr.qll | 2 +- .../swift/generated/expr/DictionaryExpr.qll | 2 +- .../generated/expr/DifferentiableFunctionExpr.qll | 2 +- .../DifferentiableFunctionExtractOriginalExpr.qll | 2 +- .../generated/expr/DiscardAssignmentExpr.qll | 2 +- .../codeql/swift/generated/expr/DotSelfExpr.qll | 2 +- .../generated/expr/DotSyntaxBaseIgnoredExpr.qll | 2 +- .../swift/generated/expr/DotSyntaxCallExpr.qll | 2 +- .../swift/generated/expr/DynamicMemberRefExpr.qll | 2 +- .../swift/generated/expr/DynamicSubscriptExpr.qll | 2 +- .../swift/generated/expr/DynamicTypeExpr.qll | 2 +- .../generated/expr/EditorPlaceholderExpr.qll | 2 +- .../swift/generated/expr/EnumIsCaseExpr.qll | 2 +- .../codeql/swift/generated/expr/ErasureExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/ErrorExpr.qll | 2 +- .../expr/ExistentialMetatypeToObjectExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/Expr.qll | 2 ++ .../swift/generated/expr/FloatLiteralExpr.qll | 2 +- .../codeql/swift/generated/expr/ForceTryExpr.qll | 2 +- .../swift/generated/expr/ForceValueExpr.qll | 2 +- .../generated/expr/ForcedCheckedCastExpr.qll | 2 +- .../expr/ForeignObjectConversionExpr.qll | 2 +- .../generated/expr/FunctionConversionExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/IfExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/InOutExpr.qll | 2 +- .../swift/generated/expr/InOutToPointerExpr.qll | 2 +- .../generated/expr/InjectIntoOptionalExpr.qll | 2 +- .../swift/generated/expr/IntegerLiteralExpr.qll | 2 +- .../expr/InterpolatedStringLiteralExpr.qll | 10 +++++++++- .../ql/lib/codeql/swift/generated/expr/IsExpr.qll | 2 +- .../generated/expr/KeyPathApplicationExpr.qll | 2 +- .../swift/generated/expr/KeyPathDotExpr.qll | 2 +- .../codeql/swift/generated/expr/KeyPathExpr.qll | 6 +++++- .../swift/generated/expr/LazyInitializerExpr.qll | 2 +- .../swift/generated/expr/LinearFunctionExpr.qll | 2 +- .../expr/LinearFunctionExtractOriginalExpr.qll | 2 +- .../expr/LinearToDifferentiableFunctionExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/LoadExpr.qll | 2 +- .../generated/expr/MagicIdentifierLiteralExpr.qll | 2 +- .../expr/MakeTemporarilyEscapableExpr.qll | 2 +- .../codeql/swift/generated/expr/MemberRefExpr.qll | 2 +- .../generated/expr/MetatypeConversionExpr.qll | 2 +- .../swift/generated/expr/NilLiteralExpr.qll | 2 +- .../swift/generated/expr/ObjCSelectorExpr.qll | 2 +- .../swift/generated/expr/ObjectLiteralExpr.qll | 2 +- .../codeql/swift/generated/expr/OneWayExpr.qll | 2 +- .../swift/generated/expr/OpaqueValueExpr.qll | 2 +- .../swift/generated/expr/OpenExistentialExpr.qll | 2 +- .../generated/expr/OptionalEvaluationExpr.qll | 2 +- .../swift/generated/expr/OptionalTryExpr.qll | 2 +- .../expr/OtherConstructorDeclRefExpr.qll | 2 +- .../generated/expr/OverloadedDeclRefExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/ParenExpr.qll | 2 +- .../swift/generated/expr/PointerToPointerExpr.qll | 2 +- .../swift/generated/expr/PostfixUnaryExpr.qll | 2 +- .../swift/generated/expr/PrefixUnaryExpr.qll | 2 +- .../expr/PropertyWrapperValuePlaceholderExpr.qll | 2 +- .../expr/ProtocolMetatypeToObjectExpr.qll | 2 +- .../expr/RebindSelfInConstructorExpr.qll | 2 +- .../swift/generated/expr/RegexLiteralExpr.qll | 2 +- .../codeql/swift/generated/expr/SequenceExpr.qll | 2 +- .../swift/generated/expr/StringLiteralExpr.qll | 2 +- .../swift/generated/expr/StringToPointerExpr.qll | 2 +- .../codeql/swift/generated/expr/SubscriptExpr.qll | 2 +- .../codeql/swift/generated/expr/SuperRefExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/TapExpr.qll | 4 +++- .../lib/codeql/swift/generated/expr/TryExpr.qll | 2 +- .../swift/generated/expr/TupleElementExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/TupleExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/TypeExpr.qll | 4 +++- .../generated/expr/UnderlyingToOpaqueExpr.qll | 2 +- .../generated/expr/UnevaluatedInstanceExpr.qll | 2 +- .../generated/expr/UnresolvedDeclRefExpr.qll | 2 +- .../swift/generated/expr/UnresolvedDotExpr.qll | 2 +- .../expr/UnresolvedMemberChainResultExpr.qll | 2 +- .../swift/generated/expr/UnresolvedMemberExpr.qll | 2 +- .../generated/expr/UnresolvedPatternExpr.qll | 2 +- .../generated/expr/UnresolvedSpecializeExpr.qll | 2 +- .../expr/UnresolvedTypeConversionExpr.qll | 2 +- .../swift/generated/expr/VarargExpansionExpr.qll | 2 +- .../codeql/swift/generated/pattern/AnyPattern.qll | 2 +- .../swift/generated/pattern/BindingPattern.qll | 2 +- .../swift/generated/pattern/BoolPattern.qll | 2 +- .../generated/pattern/EnumElementPattern.qll | 4 +++- .../swift/generated/pattern/ExprPattern.qll | 2 +- .../codeql/swift/generated/pattern/IsPattern.qll | 6 +++++- .../swift/generated/pattern/NamedPattern.qll | 2 +- .../generated/pattern/OptionalSomePattern.qll | 2 +- .../swift/generated/pattern/ParenPattern.qll | 2 +- .../swift/generated/pattern/TuplePattern.qll | 2 +- .../swift/generated/pattern/TypedPattern.qll | 4 +++- .../lib/codeql/swift/generated/stmt/BraceStmt.qll | 2 +- .../lib/codeql/swift/generated/stmt/BreakStmt.qll | 6 +++++- .../codeql/swift/generated/stmt/CaseLabelItem.qll | 4 +++- .../lib/codeql/swift/generated/stmt/CaseStmt.qll | 2 +- .../swift/generated/stmt/ConditionElement.qll | 8 +++++++- .../codeql/swift/generated/stmt/ContinueStmt.qll | 6 +++++- .../lib/codeql/swift/generated/stmt/DeferStmt.qll | 2 +- .../codeql/swift/generated/stmt/DoCatchStmt.qll | 2 +- .../ql/lib/codeql/swift/generated/stmt/DoStmt.qll | 2 +- .../lib/codeql/swift/generated/stmt/FailStmt.qll | 2 +- .../swift/generated/stmt/FallthroughStmt.qll | 2 +- .../codeql/swift/generated/stmt/ForEachStmt.qll | 4 +++- .../lib/codeql/swift/generated/stmt/GuardStmt.qll | 2 +- .../ql/lib/codeql/swift/generated/stmt/IfStmt.qll | 4 +++- .../codeql/swift/generated/stmt/LabeledStmt.qll | 2 ++ .../swift/generated/stmt/PoundAssertStmt.qll | 2 +- .../swift/generated/stmt/RepeatWhileStmt.qll | 2 +- .../codeql/swift/generated/stmt/ReturnStmt.qll | 4 +++- .../codeql/swift/generated/stmt/StmtCondition.qll | 2 +- .../codeql/swift/generated/stmt/SwitchStmt.qll | 2 +- .../lib/codeql/swift/generated/stmt/ThrowStmt.qll | 2 +- .../lib/codeql/swift/generated/stmt/WhileStmt.qll | 2 +- .../lib/codeql/swift/generated/stmt/YieldStmt.qll | 2 +- .../swift/generated/type/AnyGenericType.qll | 2 ++ .../swift/generated/type/ArraySliceType.qll | 2 +- .../generated/type/BoundGenericClassType.qll | 2 +- .../swift/generated/type/BoundGenericEnumType.qll | 2 +- .../generated/type/BoundGenericStructType.qll | 2 +- .../generated/type/BuiltinBridgeObjectType.qll | 2 +- .../type/BuiltinDefaultActorStorageType.qll | 2 +- .../swift/generated/type/BuiltinExecutorType.qll | 2 +- .../swift/generated/type/BuiltinFloatType.qll | 2 +- .../generated/type/BuiltinIntegerLiteralType.qll | 2 +- .../swift/generated/type/BuiltinIntegerType.qll | 2 +- .../swift/generated/type/BuiltinJobType.qll | 2 +- .../generated/type/BuiltinNativeObjectType.qll | 2 +- .../generated/type/BuiltinRawPointerType.qll | 2 +- .../type/BuiltinRawUnsafeContinuationType.qll | 2 +- .../type/BuiltinUnsafeValueBufferType.qll | 2 +- .../swift/generated/type/BuiltinVectorType.qll | 2 +- .../lib/codeql/swift/generated/type/ClassType.qll | 2 +- .../swift/generated/type/DependentMemberType.qll | 2 +- .../swift/generated/type/DictionaryType.qll | 2 +- .../swift/generated/type/DynamicSelfType.qll | 2 +- .../lib/codeql/swift/generated/type/EnumType.qll | 2 +- .../lib/codeql/swift/generated/type/ErrorType.qll | 2 +- .../generated/type/ExistentialMetatypeType.qll | 2 +- .../swift/generated/type/ExistentialType.qll | 2 +- .../codeql/swift/generated/type/FunctionType.qll | 2 +- .../swift/generated/type/GenericFunctionType.qll | 2 +- .../swift/generated/type/GenericTypeParamType.qll | 2 +- .../lib/codeql/swift/generated/type/InOutType.qll | 2 +- .../codeql/swift/generated/type/LValueType.qll | 2 +- .../codeql/swift/generated/type/MetatypeType.qll | 2 +- .../codeql/swift/generated/type/ModuleType.qll | 2 +- .../swift/generated/type/NestedArchetypeType.qll | 2 +- .../generated/type/OpaqueTypeArchetypeType.qll | 2 +- .../swift/generated/type/OpenedArchetypeType.qll | 2 +- .../codeql/swift/generated/type/OptionalType.qll | 2 +- .../lib/codeql/swift/generated/type/ParenType.qll | 2 +- .../swift/generated/type/PlaceholderType.qll | 2 +- .../swift/generated/type/PrimaryArchetypeType.qll | 2 +- .../generated/type/ProtocolCompositionType.qll | 2 +- .../codeql/swift/generated/type/ProtocolType.qll | 2 +- .../generated/type/SequenceArchetypeType.qll | 2 +- .../swift/generated/type/SilBlockStorageType.qll | 2 +- .../codeql/swift/generated/type/SilBoxType.qll | 2 +- .../swift/generated/type/SilFunctionType.qll | 2 +- .../codeql/swift/generated/type/SilTokenType.qll | 2 +- .../codeql/swift/generated/type/StructType.qll | 2 +- .../lib/codeql/swift/generated/type/TupleType.qll | 2 +- .../codeql/swift/generated/type/TypeAliasType.qll | 2 +- .../swift/generated/type/TypeVariableType.qll | 2 +- .../swift/generated/type/UnboundGenericType.qll | 2 +- .../codeql/swift/generated/type/UnknownType.qll | 2 +- .../swift/generated/type/UnmanagedStorageType.qll | 2 +- .../swift/generated/type/UnownedStorageType.qll | 2 +- .../swift/generated/type/UnresolvedType.qll | 2 +- .../swift/generated/type/VariadicSequenceType.qll | 2 +- .../swift/generated/type/WeakStorageType.qll | 2 +- 246 files changed, 351 insertions(+), 263 deletions(-) diff --git a/swift/codegen/cppgen.py b/swift/codegen/cppgen.py index eee66a812f0..623621e3559 100644 --- a/swift/codegen/cppgen.py +++ b/swift/codegen/cppgen.py @@ -27,7 +27,7 @@ def _get_field(cls: schema.Class, p: schema.Property, trap_affix: str) -> cpp.Fi if not p.is_predicate: trap_name = inflection.pluralize(trap_name) args = dict( - name=p.name + ("_" if p.name in cpp.cpp_keywords else ""), + field_name=p.name + ("_" if p.name in cpp.cpp_keywords else ""), type=_get_type(p.type, trap_affix), is_optional=p.is_optional, is_repeated=p.is_repeated, diff --git a/swift/codegen/lib/cpp.py b/swift/codegen/lib/cpp.py index 82dfbb44bcb..71bb364b74b 100644 --- a/swift/codegen/lib/cpp.py +++ b/swift/codegen/lib/cpp.py @@ -17,7 +17,7 @@ cpp_keywords = {"alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", " _field_overrides = [ (re.compile(r"(start|end)_(line|column)|index|width|num_.*"), {"type": "unsigned"}), - (re.compile(r"(.*)_"), lambda m: {"name": m[1]}), + (re.compile(r"(.*)_"), lambda m: {"field_name": m[1]}), ] @@ -31,7 +31,7 @@ def get_field_override(field: str): @dataclass class Field: - name: str + field_name: str type: str is_optional: bool = False is_repeated: bool = False @@ -44,12 +44,8 @@ class Field: self.type = f"std::optional<{self.type}>" if self.is_repeated: self.type = f"std::vector<{self.type}>" - - @property - def cpp_name(self): - if self.name in cpp_keywords: - return self.name + "_" - return self.name + if self.field_name in cpp_keywords: + self.field_name += "_" # using @property breaks pystache internals here def get_streamer(self): @@ -65,8 +61,6 @@ class Field: return not (self.is_optional or self.is_repeated or self.is_predicate) - - @dataclass class Trap: table_name: str diff --git a/swift/codegen/lib/schema.py b/swift/codegen/lib/schema.py index a65aaf24dca..648b8b2ec64 100644 --- a/swift/codegen/lib/schema.py +++ b/swift/codegen/lib/schema.py @@ -92,7 +92,6 @@ def load(path): data = yaml.load(input, Loader=yaml.SafeLoader) grouper = _DirSelector(data.get("_directories", {}).items()) classes = {root_class_name: Class(root_class_name)} - assert root_class_name not in data classes.update((cls, Class(cls, dir=grouper.get(cls))) for cls in data if not cls.startswith("_")) for name, info in data.items(): if name.startswith("_"): @@ -110,7 +109,7 @@ def load(path): classes[base].derived.add(name) elif k == "_dir": cls.dir = pathlib.Path(v) - if not cls.bases: + if not cls.bases and cls.name != root_class_name: cls.bases.add(root_class_name) classes[root_class_name].derived.add(name) diff --git a/swift/codegen/templates/cpp_classes.mustache b/swift/codegen/templates/cpp_classes.mustache index 15e33a378dc..fdaf52e3efe 100644 --- a/swift/codegen/templates/cpp_classes.mustache +++ b/swift/codegen/templates/cpp_classes.mustache @@ -14,7 +14,7 @@ namespace {{namespace}} { struct {{name}}{{#final}} : Binding<{{name}}Tag>{{#bases}}, {{ref.name}}{{/bases}}{{/final}}{{^final}}{{#has_bases}}: {{#bases}}{{^first}}, {{/first}}{{ref.name}}{{/bases}}{{/has_bases}}{{/final}} { {{#fields}} - {{type}} {{name}}{}; + {{type}} {{field_name}}{}; {{/fields}} {{#final}} @@ -27,27 +27,27 @@ struct {{name}}{{#final}} : Binding<{{name}}Tag>{{#bases}}, {{ref.name}}{{/bases protected: void emit({{^final}}{{trap_affix}}Label<{{name}}Tag> id, {{/final}}std::ostream& out) const { {{#trap_name}} - out << {{.}}{{trap_affix}}{id{{#single_fields}}, {{name}}{{/single_fields}}} << '\n'; + out << {{.}}{{trap_affix}}{id{{#single_fields}}, {{field_name}}{{/single_fields}}} << '\n'; {{/trap_name}} {{#bases}} {{ref.name}}::emit(id, out); {{/bases}} {{#fields}} {{#is_predicate}} - if ({{name}}) out << {{trap_name}}{{trap_affix}}{id} << '\n'; + if ({{field_name}}) out << {{trap_name}}{{trap_affix}}{id} << '\n'; {{/is_predicate}} {{#is_optional}} {{^is_repeated}} - if ({{name}}) out << {{trap_name}}{{trap_affix}}{id, *{{name}}} << '\n'; + if ({{field_name}}) out << {{trap_name}}{{trap_affix}}{id, *{{field_name}}} << '\n'; {{/is_repeated}} {{/is_optional}} {{#is_repeated}} - for (auto i = 0u; i < {{name}}.size(); ++i) { + for (auto i = 0u; i < {{field_name}}.size(); ++i) { {{^is_optional}} - out << {{trap_name}}{{trap_affix}}{id, i, {{name}}[i]}; + out << {{trap_name}}{{trap_affix}}{id, i, {{field_name}}[i]}; {{/is_optional}} {{#is_optional}} - if ({{name}}[i]) out << {{trap_name}}{{trap_affix}}{id, i, *{{name}}[i]}; + if ({{field_name}}[i]) out << {{trap_name}}{{trap_affix}}{id, i, *{{field_name}}[i]}; {{/is_optional}} } {{/is_repeated}} diff --git a/swift/codegen/templates/ql_class.mustache b/swift/codegen/templates/ql_class.mustache index 89da396be90..3c54467b7c4 100644 --- a/swift/codegen/templates/ql_class.mustache +++ b/swift/codegen/templates/ql_class.mustache @@ -8,6 +8,8 @@ class {{name}}Base extends {{db_id}}{{#bases}}, {{.}}{{/bases}} { {{#root}} string toString() { none() } // overridden by subclasses + string getPrimaryQlClass() { none() } // overridden by subclasses + {{name}}Base getResolveStep() { none() } // overridden by subclasses {{name}}Base resolve() { @@ -17,7 +19,7 @@ class {{name}}Base extends {{db_id}}{{#bases}}, {{.}}{{/bases}} { } {{/root}} {{#final}} - override string toString() { result = "{{name}}" } + override string getPrimaryQlClass() { result = "{{name}}" } {{/final}} {{#properties}} @@ -32,6 +34,12 @@ class {{name}}Base extends {{db_id}}{{#bases}}, {{.}}{{/bases}} { {{tablename}}({{#tableparams}}{{^first}}, {{/first}}{{param}}{{/tableparams}}) {{/type_is_class}} } + {{#is_optional}} + + predicate has{{singular}}({{#is_repeated}}int index{{/is_repeated}}) { + exists({{getter}}({{#is_repeated}}index{{/is_repeated}})) + } + {{/is_optional}} {{#is_repeated}} {{type}} {{indefinite_getter}}() { diff --git a/swift/codegen/templates/trap_traps.mustache b/swift/codegen/templates/trap_traps.mustache index 1848d3fbc87..a6b75a597d8 100644 --- a/swift/codegen/templates/trap_traps.mustache +++ b/swift/codegen/templates/trap_traps.mustache @@ -6,6 +6,7 @@ #include #include "{{include_dir}}/{{trap_affix}}Label.h" +#include "{{include_dir}}/{{trap_affix}}TagTraits.h" #include "./{{trap_affix}}Tags.h" namespace {{namespace}} { @@ -15,19 +16,25 @@ namespace {{namespace}} { struct {{name}}{{trap_affix}} { static constexpr bool is_binding = {{#id}}true{{/id}}{{^id}}false{{/id}}; {{#id}} - {{type}} getBoundLabel() const { return {{cpp_name}}; } + {{type}} getBoundLabel() const { return {{field_name}}; } {{/id}} {{#fields}} - {{type}} {{cpp_name}}{}; + {{type}} {{field_name}}{}; {{/fields}} }; inline std::ostream &operator<<(std::ostream &out, const {{name}}{{trap_affix}} &e) { out << "{{table_name}}("{{#fields}}{{^first}} << ", "{{/first}} - << {{#get_streamer}}e.{{cpp_name}}{{/get_streamer}}{{/fields}} << ")"; + << {{#get_streamer}}e.{{field_name}}{{/get_streamer}}{{/fields}} << ")"; return out; } -{{/traps}} +{{#id}} +template <> +struct TagToBindingTrapFunctor { + using type = {{name}}{{trap_affix}}; +}; +{{/id}} +{{/traps}} } diff --git a/swift/codegen/test/test_cpp.py b/swift/codegen/test/test_cpp.py index 06ff50f8a51..e6cd4f81305 100644 --- a/swift/codegen/test/test_cpp.py +++ b/swift/codegen/test/test_cpp.py @@ -7,14 +7,14 @@ from swift.codegen.lib import cpp @pytest.mark.parametrize("keyword", cpp.cpp_keywords) -def test_field_keyword_cpp_name(keyword): +def test_field_keyword_name(keyword): f = cpp.Field(keyword, "int") - assert f.cpp_name == keyword + "_" + assert f.field_name == keyword + "_" -def test_field_cpp_name(): +def test_field_name(): f = cpp.Field("foo", "int") - assert f.cpp_name == "foo" + assert f.field_name == "foo" @pytest.mark.parametrize("type,expected", [ diff --git a/swift/codegen/test/test_schema.py b/swift/codegen/test/test_schema.py index c1b64648894..cbeb9c6989a 100644 --- a/swift/codegen/test/test_schema.py +++ b/swift/codegen/test/test_schema.py @@ -155,5 +155,17 @@ A: ] +def test_element_properties(load): + ret = load(""" +Element: + x: string +""") + assert ret.classes == [ + schema.Class(root_name, properties=[ + schema.SingleProperty('x', 'string'), + ]), + ] + + if __name__ == '__main__': sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/trapgen.py b/swift/codegen/trapgen.py index 495a51a8388..ed2fef4373b 100755 --- a/swift/codegen/trapgen.py +++ b/swift/codegen/trapgen.py @@ -28,7 +28,7 @@ def get_cpp_type(schema_type: str, trap_affix: str): def get_field(c: dbscheme.Column, trap_affix: str): args = { - "name": c.schema_name, + "field_name": c.schema_name, "type": c.type, } args.update(cpp.get_field_override(c.schema_name)) diff --git a/swift/extractor/trap/TrapLabel.h b/swift/extractor/trap/TrapLabel.h index 9928bb9a2b9..b601b5c041a 100644 --- a/swift/extractor/trap/TrapLabel.h +++ b/swift/extractor/trap/TrapLabel.h @@ -27,7 +27,7 @@ class UntypedTrapLabel { friend bool operator==(UntypedTrapLabel lhs, UntypedTrapLabel rhs) { return lhs.id_ == rhs.id_; } }; -template +template class TrapLabel : public UntypedTrapLabel { template friend class TrapLabel; @@ -35,6 +35,8 @@ class TrapLabel : public UntypedTrapLabel { using UntypedTrapLabel::UntypedTrapLabel; public: + using Tag = TagParam; + TrapLabel() = default; template diff --git a/swift/extractor/trap/TrapTagTraits.h b/swift/extractor/trap/TrapTagTraits.h index 280474b5304..930127403ac 100644 --- a/swift/extractor/trap/TrapTagTraits.h +++ b/swift/extractor/trap/TrapTagTraits.h @@ -2,7 +2,7 @@ #include -namespace codeql::trap { +namespace codeql { template struct ToTagFunctor; @@ -12,4 +12,10 @@ struct ToTagOverride : ToTagFunctor {}; template using ToTag = typename ToTagOverride>::type; -} // namespace codeql::trap +template +struct TagToBindingTrapFunctor; + +template +using TagToBindingTrap = typename TagToBindingTrapFunctor::type; + +} // namespace codeql diff --git a/swift/ql/lib/codeql/swift/generated/Element.qll b/swift/ql/lib/codeql/swift/generated/Element.qll index fcb8e68c86f..e9f54415ac1 100644 --- a/swift/ql/lib/codeql/swift/generated/Element.qll +++ b/swift/ql/lib/codeql/swift/generated/Element.qll @@ -2,6 +2,8 @@ class ElementBase extends @element { string toString() { none() } // overridden by subclasses + string getPrimaryQlClass() { none() } // overridden by subclasses + ElementBase getResolveStep() { none() } // overridden by subclasses ElementBase resolve() { diff --git a/swift/ql/lib/codeql/swift/generated/File.qll b/swift/ql/lib/codeql/swift/generated/File.qll index 9c431346952..a0cde68c73a 100644 --- a/swift/ql/lib/codeql/swift/generated/File.qll +++ b/swift/ql/lib/codeql/swift/generated/File.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.Element class FileBase extends @file, Element { - override string toString() { result = "File" } + override string getPrimaryQlClass() { result = "File" } string getName() { files(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/Location.qll b/swift/ql/lib/codeql/swift/generated/Location.qll index e30b4f275c1..a39ee13823c 100644 --- a/swift/ql/lib/codeql/swift/generated/Location.qll +++ b/swift/ql/lib/codeql/swift/generated/Location.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.Element import codeql.swift.elements.File class LocationBase extends @location, Element { - override string toString() { result = "Location" } + override string getPrimaryQlClass() { result = "Location" } File getFile() { exists(File x | diff --git a/swift/ql/lib/codeql/swift/generated/UnknownAstNode.qll b/swift/ql/lib/codeql/swift/generated/UnknownAstNode.qll index 657db267a96..06bca7af67d 100644 --- a/swift/ql/lib/codeql/swift/generated/UnknownAstNode.qll +++ b/swift/ql/lib/codeql/swift/generated/UnknownAstNode.qll @@ -6,7 +6,7 @@ import codeql.swift.elements.stmt.Stmt import codeql.swift.elements.typerepr.TypeRepr class UnknownAstNodeBase extends @unknown_ast_node, Decl, Expr, Pattern, Stmt, TypeRepr { - override string toString() { result = "UnknownAstNode" } + override string getPrimaryQlClass() { result = "UnknownAstNode" } string getName() { unknown_ast_nodes(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/AbstractFunctionDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/AbstractFunctionDecl.qll index 26e65473f13..5a6ba0e41a7 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/AbstractFunctionDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/AbstractFunctionDecl.qll @@ -14,6 +14,8 @@ class AbstractFunctionDeclBase extends @abstract_function_decl, GenericContext, ) } + predicate hasBody() { exists(getBody()) } + ParamDecl getParam(int index) { exists(ParamDecl x | abstract_function_decl_params(this, index, x) and diff --git a/swift/ql/lib/codeql/swift/generated/decl/AccessorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/AccessorDecl.qll index 6be785a6ece..5ac3dd7091a 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/AccessorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/AccessorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.FuncDecl class AccessorDeclBase extends @accessor_decl, FuncDecl { - override string toString() { result = "AccessorDecl" } + override string getPrimaryQlClass() { result = "AccessorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/AssociatedTypeDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/AssociatedTypeDecl.qll index fbcfb20c3ed..e7970236870 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/AssociatedTypeDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/AssociatedTypeDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.AbstractTypeParamDecl class AssociatedTypeDeclBase extends @associated_type_decl, AbstractTypeParamDecl { - override string toString() { result = "AssociatedTypeDecl" } + override string getPrimaryQlClass() { result = "AssociatedTypeDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ClassDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ClassDecl.qll index 96a9cc587c5..07d6d63128f 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ClassDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ClassDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.NominalTypeDecl class ClassDeclBase extends @class_decl, NominalTypeDecl { - override string toString() { result = "ClassDecl" } + override string getPrimaryQlClass() { result = "ClassDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ConcreteFuncDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ConcreteFuncDecl.qll index b46b4745537..e34421da66d 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ConcreteFuncDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ConcreteFuncDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.FuncDecl class ConcreteFuncDeclBase extends @concrete_func_decl, FuncDecl { - override string toString() { result = "ConcreteFuncDecl" } + override string getPrimaryQlClass() { result = "ConcreteFuncDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ConcreteVarDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ConcreteVarDecl.qll index f94ee9cad28..c6564834c5f 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ConcreteVarDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ConcreteVarDecl.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.decl.VarDecl class ConcreteVarDeclBase extends @concrete_var_decl, VarDecl { - override string toString() { result = "ConcreteVarDecl" } + override string getPrimaryQlClass() { result = "ConcreteVarDecl" } int getIntroducerInt() { concrete_var_decls(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ConstructorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ConstructorDecl.qll index cc73243e409..fbd9db1e299 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ConstructorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ConstructorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.AbstractFunctionDecl class ConstructorDeclBase extends @constructor_decl, AbstractFunctionDecl { - override string toString() { result = "ConstructorDecl" } + override string getPrimaryQlClass() { result = "ConstructorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/DestructorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/DestructorDecl.qll index 3223ab2d196..667650662a0 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/DestructorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/DestructorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.AbstractFunctionDecl class DestructorDeclBase extends @destructor_decl, AbstractFunctionDecl { - override string toString() { result = "DestructorDecl" } + override string getPrimaryQlClass() { result = "DestructorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/EnumCaseDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/EnumCaseDecl.qll index ef87a7a2de6..654da108fa0 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/EnumCaseDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/EnumCaseDecl.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.decl.Decl import codeql.swift.elements.decl.EnumElementDecl class EnumCaseDeclBase extends @enum_case_decl, Decl { - override string toString() { result = "EnumCaseDecl" } + override string getPrimaryQlClass() { result = "EnumCaseDecl" } EnumElementDecl getElement(int index) { exists(EnumElementDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/decl/EnumDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/EnumDecl.qll index e1c78ecadd0..75120af5548 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/EnumDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/EnumDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.NominalTypeDecl class EnumDeclBase extends @enum_decl, NominalTypeDecl { - override string toString() { result = "EnumDecl" } + override string getPrimaryQlClass() { result = "EnumDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/EnumElementDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/EnumElementDecl.qll index ace35b89318..0210e22ddda 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/EnumElementDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/EnumElementDecl.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.decl.ParamDecl import codeql.swift.elements.decl.ValueDecl class EnumElementDeclBase extends @enum_element_decl, ValueDecl { - override string toString() { result = "EnumElementDecl" } + override string getPrimaryQlClass() { result = "EnumElementDecl" } string getName() { enum_element_decls(this, result) } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ExtensionDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ExtensionDecl.qll index 653f791ec76..fff23dbeb47 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ExtensionDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ExtensionDecl.qll @@ -4,5 +4,5 @@ import codeql.swift.elements.decl.GenericContext import codeql.swift.elements.decl.IterableDeclContext class ExtensionDeclBase extends @extension_decl, Decl, GenericContext, IterableDeclContext { - override string toString() { result = "ExtensionDecl" } + override string getPrimaryQlClass() { result = "ExtensionDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/GenericTypeParamDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/GenericTypeParamDecl.qll index effe651ea5e..9cc79737f0b 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/GenericTypeParamDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/GenericTypeParamDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.AbstractTypeParamDecl class GenericTypeParamDeclBase extends @generic_type_param_decl, AbstractTypeParamDecl { - override string toString() { result = "GenericTypeParamDecl" } + override string getPrimaryQlClass() { result = "GenericTypeParamDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/IfConfigDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/IfConfigDecl.qll index 6d53786e2c3..bcc629577d9 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/IfConfigDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/IfConfigDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.Decl class IfConfigDeclBase extends @if_config_decl, Decl { - override string toString() { result = "IfConfigDecl" } + override string getPrimaryQlClass() { result = "IfConfigDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ImportDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ImportDecl.qll index 53b2e7d9804..e2b9a59a72d 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ImportDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ImportDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.Decl class ImportDeclBase extends @import_decl, Decl { - override string toString() { result = "ImportDecl" } + override string getPrimaryQlClass() { result = "ImportDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/InfixOperatorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/InfixOperatorDecl.qll index 4c91bed5227..bac4345e86d 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/InfixOperatorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/InfixOperatorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.OperatorDecl class InfixOperatorDeclBase extends @infix_operator_decl, OperatorDecl { - override string toString() { result = "InfixOperatorDecl" } + override string getPrimaryQlClass() { result = "InfixOperatorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/MissingMemberDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/MissingMemberDecl.qll index 19131ef4d9a..046fece53b5 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/MissingMemberDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/MissingMemberDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.Decl class MissingMemberDeclBase extends @missing_member_decl, Decl { - override string toString() { result = "MissingMemberDecl" } + override string getPrimaryQlClass() { result = "MissingMemberDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ModuleDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ModuleDecl.qll index f9337f91618..94fac5a140b 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ModuleDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ModuleDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.TypeDecl class ModuleDeclBase extends @module_decl, TypeDecl { - override string toString() { result = "ModuleDecl" } + override string getPrimaryQlClass() { result = "ModuleDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/OpaqueTypeDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/OpaqueTypeDecl.qll index 5e1e176aa38..87307cf27b1 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/OpaqueTypeDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/OpaqueTypeDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.GenericTypeDecl class OpaqueTypeDeclBase extends @opaque_type_decl, GenericTypeDecl { - override string toString() { result = "OpaqueTypeDecl" } + override string getPrimaryQlClass() { result = "OpaqueTypeDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ParamDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ParamDecl.qll index e2f3b0a8d49..455f504e777 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ParamDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ParamDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.VarDecl class ParamDeclBase extends @param_decl, VarDecl { - override string toString() { result = "ParamDecl" } + override string getPrimaryQlClass() { result = "ParamDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll index 9d693c9f9c7..6b69930402e 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.pattern.Pattern class PatternBindingDeclBase extends @pattern_binding_decl, Decl { - override string toString() { result = "PatternBindingDecl" } + override string getPrimaryQlClass() { result = "PatternBindingDecl" } Expr getInit(int index) { exists(Expr x | @@ -13,6 +13,8 @@ class PatternBindingDeclBase extends @pattern_binding_decl, Decl { ) } + predicate hasInit(int index) { exists(getInit(index)) } + Expr getAnInit() { result = getInit(_) } Pattern getPattern(int index) { diff --git a/swift/ql/lib/codeql/swift/generated/decl/PostfixOperatorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/PostfixOperatorDecl.qll index 94f709fa1b4..4786bb2eb08 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/PostfixOperatorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/PostfixOperatorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.OperatorDecl class PostfixOperatorDeclBase extends @postfix_operator_decl, OperatorDecl { - override string toString() { result = "PostfixOperatorDecl" } + override string getPrimaryQlClass() { result = "PostfixOperatorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/PoundDiagnosticDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/PoundDiagnosticDecl.qll index af004769c83..ba7d98fde10 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/PoundDiagnosticDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/PoundDiagnosticDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.Decl class PoundDiagnosticDeclBase extends @pound_diagnostic_decl, Decl { - override string toString() { result = "PoundDiagnosticDecl" } + override string getPrimaryQlClass() { result = "PoundDiagnosticDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/PrecedenceGroupDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/PrecedenceGroupDecl.qll index 2da8c646cf0..a963aeff10d 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/PrecedenceGroupDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/PrecedenceGroupDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.Decl class PrecedenceGroupDeclBase extends @precedence_group_decl, Decl { - override string toString() { result = "PrecedenceGroupDecl" } + override string getPrimaryQlClass() { result = "PrecedenceGroupDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/PrefixOperatorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/PrefixOperatorDecl.qll index 9620dcb1d65..01db13ad940 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/PrefixOperatorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/PrefixOperatorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.OperatorDecl class PrefixOperatorDeclBase extends @prefix_operator_decl, OperatorDecl { - override string toString() { result = "PrefixOperatorDecl" } + override string getPrimaryQlClass() { result = "PrefixOperatorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ProtocolDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ProtocolDecl.qll index 322a29acd6b..29fcf2b507a 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ProtocolDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ProtocolDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.NominalTypeDecl class ProtocolDeclBase extends @protocol_decl, NominalTypeDecl { - override string toString() { result = "ProtocolDecl" } + override string getPrimaryQlClass() { result = "ProtocolDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/StructDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/StructDecl.qll index 65459bf93c2..26455f15484 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/StructDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/StructDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.NominalTypeDecl class StructDeclBase extends @struct_decl, NominalTypeDecl { - override string toString() { result = "StructDecl" } + override string getPrimaryQlClass() { result = "StructDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/SubscriptDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/SubscriptDecl.qll index b84abbec539..6329f269f49 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/SubscriptDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/SubscriptDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.AbstractStorageDecl class SubscriptDeclBase extends @subscript_decl, AbstractStorageDecl { - override string toString() { result = "SubscriptDecl" } + override string getPrimaryQlClass() { result = "SubscriptDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/TopLevelCodeDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/TopLevelCodeDecl.qll index 9d460066513..87899c24bfe 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/TopLevelCodeDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/TopLevelCodeDecl.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.BraceStmt import codeql.swift.elements.decl.Decl class TopLevelCodeDeclBase extends @top_level_code_decl, Decl { - override string toString() { result = "TopLevelCodeDecl" } + override string getPrimaryQlClass() { result = "TopLevelCodeDecl" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/decl/TypeAliasDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/TypeAliasDecl.qll index d4d3573614e..d5a41a716bc 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/TypeAliasDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/TypeAliasDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.GenericTypeDecl class TypeAliasDeclBase extends @type_alias_decl, GenericTypeDecl { - override string toString() { result = "TypeAliasDecl" } + override string getPrimaryQlClass() { result = "TypeAliasDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/AnyHashableErasureExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/AnyHashableErasureExpr.qll index 0c9bef9b580..de5c1534faf 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/AnyHashableErasureExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/AnyHashableErasureExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class AnyHashableErasureExprBase extends @any_hashable_erasure_expr, ImplicitConversionExpr { - override string toString() { result = "AnyHashableErasureExpr" } + override string getPrimaryQlClass() { result = "AnyHashableErasureExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/AppliedPropertyWrapperExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/AppliedPropertyWrapperExpr.qll index 9aec2e17c3b..e0f95ba2a02 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/AppliedPropertyWrapperExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/AppliedPropertyWrapperExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class AppliedPropertyWrapperExprBase extends @applied_property_wrapper_expr, Expr { - override string toString() { result = "AppliedPropertyWrapperExpr" } + override string getPrimaryQlClass() { result = "AppliedPropertyWrapperExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ArchetypeToSuperExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ArchetypeToSuperExpr.qll index 51bcd473f69..e5123e26e53 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ArchetypeToSuperExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ArchetypeToSuperExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ArchetypeToSuperExprBase extends @archetype_to_super_expr, ImplicitConversionExpr { - override string toString() { result = "ArchetypeToSuperExpr" } + override string getPrimaryQlClass() { result = "ArchetypeToSuperExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/Argument.qll b/swift/ql/lib/codeql/swift/generated/expr/Argument.qll index e64f57b13f3..0a3cdae3a66 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/Argument.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/Argument.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.Element import codeql.swift.elements.expr.Expr class ArgumentBase extends @argument, Element { - override string toString() { result = "Argument" } + override string getPrimaryQlClass() { result = "Argument" } string getLabel() { arguments(this, result, _) } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ArrayExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ArrayExpr.qll index 74af871bc6b..6a9cddd47ce 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ArrayExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ArrayExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.CollectionExpr import codeql.swift.elements.expr.Expr class ArrayExprBase extends @array_expr, CollectionExpr { - override string toString() { result = "ArrayExpr" } + override string getPrimaryQlClass() { result = "ArrayExpr" } Expr getElement(int index) { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/ArrayToPointerExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ArrayToPointerExpr.qll index 9eb43a5eafe..3d1b8c96d79 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ArrayToPointerExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ArrayToPointerExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ArrayToPointerExprBase extends @array_to_pointer_expr, ImplicitConversionExpr { - override string toString() { result = "ArrayToPointerExpr" } + override string getPrimaryQlClass() { result = "ArrayToPointerExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ArrowExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ArrowExpr.qll index a42bf380eee..a8dc1d1c8fe 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ArrowExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ArrowExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class ArrowExprBase extends @arrow_expr, Expr { - override string toString() { result = "ArrowExpr" } + override string getPrimaryQlClass() { result = "ArrowExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/AssignExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/AssignExpr.qll index d5c4c81a42a..743a4de6cf0 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/AssignExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/AssignExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class AssignExprBase extends @assign_expr, Expr { - override string toString() { result = "AssignExpr" } + override string getPrimaryQlClass() { result = "AssignExpr" } Expr getDest() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/AutoClosureExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/AutoClosureExpr.qll index 4c31a494205..05cccdedea8 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/AutoClosureExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/AutoClosureExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.AbstractClosureExpr import codeql.swift.elements.stmt.BraceStmt class AutoClosureExprBase extends @auto_closure_expr, AbstractClosureExpr { - override string toString() { result = "AutoClosureExpr" } + override string getPrimaryQlClass() { result = "AutoClosureExpr" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/AwaitExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/AwaitExpr.qll index 73a79322d30..abb9a883381 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/AwaitExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/AwaitExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.IdentityExpr class AwaitExprBase extends @await_expr, IdentityExpr { - override string toString() { result = "AwaitExpr" } + override string getPrimaryQlClass() { result = "AwaitExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/BinaryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/BinaryExpr.qll index f30bfc9b2cd..e7a10adbc86 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/BinaryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/BinaryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ApplyExpr class BinaryExprBase extends @binary_expr, ApplyExpr { - override string toString() { result = "BinaryExpr" } + override string getPrimaryQlClass() { result = "BinaryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/BindOptionalExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/BindOptionalExpr.qll index 335cd5d4038..e66a617f7c5 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/BindOptionalExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/BindOptionalExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class BindOptionalExprBase extends @bind_optional_expr, Expr { - override string toString() { result = "BindOptionalExpr" } + override string getPrimaryQlClass() { result = "BindOptionalExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/BooleanLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/BooleanLiteralExpr.qll index 9eb96b658bb..98616ad15f3 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/BooleanLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/BooleanLiteralExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.BuiltinLiteralExpr class BooleanLiteralExprBase extends @boolean_literal_expr, BuiltinLiteralExpr { - override string toString() { result = "BooleanLiteralExpr" } + override string getPrimaryQlClass() { result = "BooleanLiteralExpr" } boolean getValue() { boolean_literal_exprs(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/BridgeFromObjCExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/BridgeFromObjCExpr.qll index 0494883b44f..6f5a6e38f4e 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/BridgeFromObjCExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/BridgeFromObjCExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class BridgeFromObjCExprBase extends @bridge_from_obj_c_expr, ImplicitConversionExpr { - override string toString() { result = "BridgeFromObjCExpr" } + override string getPrimaryQlClass() { result = "BridgeFromObjCExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/BridgeToObjCExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/BridgeToObjCExpr.qll index c880a148dab..39f31e77f55 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/BridgeToObjCExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/BridgeToObjCExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class BridgeToObjCExprBase extends @bridge_to_obj_c_expr, ImplicitConversionExpr { - override string toString() { result = "BridgeToObjCExpr" } + override string getPrimaryQlClass() { result = "BridgeToObjCExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CallExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CallExpr.qll index 3fa6f1eef40..6a3329711e6 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CallExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CallExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ApplyExpr class CallExprBase extends @call_expr, ApplyExpr { - override string toString() { result = "CallExpr" } + override string getPrimaryQlClass() { result = "CallExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CaptureListExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CaptureListExpr.qll index 6f7985c2098..76aac82934e 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CaptureListExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CaptureListExpr.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.decl.PatternBindingDecl class CaptureListExprBase extends @capture_list_expr, Expr { - override string toString() { result = "CaptureListExpr" } + override string getPrimaryQlClass() { result = "CaptureListExpr" } PatternBindingDecl getBindingDecl(int index) { exists(PatternBindingDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/ClassMetatypeToObjectExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ClassMetatypeToObjectExpr.qll index b06e736ec5b..ec91100ecde 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ClassMetatypeToObjectExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ClassMetatypeToObjectExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ClassMetatypeToObjectExprBase extends @class_metatype_to_object_expr, ImplicitConversionExpr { - override string toString() { result = "ClassMetatypeToObjectExpr" } + override string getPrimaryQlClass() { result = "ClassMetatypeToObjectExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ClosureExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ClosureExpr.qll index 97439eb8316..5e8022d348c 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ClosureExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ClosureExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.AbstractClosureExpr import codeql.swift.elements.stmt.BraceStmt class ClosureExprBase extends @closure_expr, AbstractClosureExpr { - override string toString() { result = "ClosureExpr" } + override string getPrimaryQlClass() { result = "ClosureExpr" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/CodeCompletionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CodeCompletionExpr.qll index 31653297bde..34b3bb695b6 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CodeCompletionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CodeCompletionExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class CodeCompletionExprBase extends @code_completion_expr, Expr { - override string toString() { result = "CodeCompletionExpr" } + override string getPrimaryQlClass() { result = "CodeCompletionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CoerceExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CoerceExpr.qll index 4d7df95eb6b..90db24a184b 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CoerceExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CoerceExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ExplicitCastExpr class CoerceExprBase extends @coerce_expr, ExplicitCastExpr { - override string toString() { result = "CoerceExpr" } + override string getPrimaryQlClass() { result = "CoerceExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CollectionUpcastConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CollectionUpcastConversionExpr.qll index 434261d6fc2..7e3bd15a64c 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CollectionUpcastConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CollectionUpcastConversionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class CollectionUpcastConversionExprBase extends @collection_upcast_conversion_expr, ImplicitConversionExpr { - override string toString() { result = "CollectionUpcastConversionExpr" } + override string getPrimaryQlClass() { result = "CollectionUpcastConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ConditionalBridgeFromObjCExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ConditionalBridgeFromObjCExpr.qll index dfdde979082..05a627f8274 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ConditionalBridgeFromObjCExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ConditionalBridgeFromObjCExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ConditionalBridgeFromObjCExprBase extends @conditional_bridge_from_obj_c_expr, ImplicitConversionExpr { - override string toString() { result = "ConditionalBridgeFromObjCExpr" } + override string getPrimaryQlClass() { result = "ConditionalBridgeFromObjCExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ConditionalCheckedCastExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ConditionalCheckedCastExpr.qll index 3a6ecc63714..bfc5a53cb8d 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ConditionalCheckedCastExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ConditionalCheckedCastExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.CheckedCastExpr class ConditionalCheckedCastExprBase extends @conditional_checked_cast_expr, CheckedCastExpr { - override string toString() { result = "ConditionalCheckedCastExpr" } + override string getPrimaryQlClass() { result = "ConditionalCheckedCastExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ConstructorRefCallExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ConstructorRefCallExpr.qll index cd573bd87d6..33d454916ca 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ConstructorRefCallExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ConstructorRefCallExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.SelfApplyExpr class ConstructorRefCallExprBase extends @constructor_ref_call_expr, SelfApplyExpr { - override string toString() { result = "ConstructorRefCallExpr" } + override string getPrimaryQlClass() { result = "ConstructorRefCallExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CovariantFunctionConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CovariantFunctionConversionExpr.qll index f641ee17558..1fec877c953 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CovariantFunctionConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CovariantFunctionConversionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class CovariantFunctionConversionExprBase extends @covariant_function_conversion_expr, ImplicitConversionExpr { - override string toString() { result = "CovariantFunctionConversionExpr" } + override string getPrimaryQlClass() { result = "CovariantFunctionConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CovariantReturnConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CovariantReturnConversionExpr.qll index 79b86e32eec..4e7199cdc33 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CovariantReturnConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CovariantReturnConversionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class CovariantReturnConversionExprBase extends @covariant_return_conversion_expr, ImplicitConversionExpr { - override string toString() { result = "CovariantReturnConversionExpr" } + override string getPrimaryQlClass() { result = "CovariantReturnConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DeclRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DeclRefExpr.qll index 08816d46d36..7093a892a74 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DeclRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DeclRefExpr.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.type.Type class DeclRefExprBase extends @decl_ref_expr, Expr { - override string toString() { result = "DeclRefExpr" } + override string getPrimaryQlClass() { result = "DeclRefExpr" } Decl getDecl() { exists(Decl x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/DefaultArgumentExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DefaultArgumentExpr.qll index a4954a6214b..6374fa961f9 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DefaultArgumentExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DefaultArgumentExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.decl.ParamDecl class DefaultArgumentExprBase extends @default_argument_expr, Expr { - override string toString() { result = "DefaultArgumentExpr" } + override string getPrimaryQlClass() { result = "DefaultArgumentExpr" } ParamDecl getParamDecl() { exists(ParamDecl x | @@ -20,4 +20,6 @@ class DefaultArgumentExprBase extends @default_argument_expr, Expr { result = x.resolve() ) } + + predicate hasCallerSideDefault() { exists(getCallerSideDefault()) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DerivedToBaseExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DerivedToBaseExpr.qll index 627944b988c..554eb512d5a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DerivedToBaseExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DerivedToBaseExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class DerivedToBaseExprBase extends @derived_to_base_expr, ImplicitConversionExpr { - override string toString() { result = "DerivedToBaseExpr" } + override string getPrimaryQlClass() { result = "DerivedToBaseExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DestructureTupleExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DestructureTupleExpr.qll index 7118ab2f2a0..b7b376b7f38 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DestructureTupleExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DestructureTupleExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class DestructureTupleExprBase extends @destructure_tuple_expr, ImplicitConversionExpr { - override string toString() { result = "DestructureTupleExpr" } + override string getPrimaryQlClass() { result = "DestructureTupleExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DictionaryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DictionaryExpr.qll index 8e9e896db3a..49fe6818051 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DictionaryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DictionaryExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.CollectionExpr import codeql.swift.elements.expr.Expr class DictionaryExprBase extends @dictionary_expr, CollectionExpr { - override string toString() { result = "DictionaryExpr" } + override string getPrimaryQlClass() { result = "DictionaryExpr" } Expr getElement(int index) { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExpr.qll index 47e6c0235aa..e864e68e73a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class DifferentiableFunctionExprBase extends @differentiable_function_expr, ImplicitConversionExpr { - override string toString() { result = "DifferentiableFunctionExpr" } + override string getPrimaryQlClass() { result = "DifferentiableFunctionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExtractOriginalExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExtractOriginalExpr.qll index c28b0947cbd..790877fa186 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExtractOriginalExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExtractOriginalExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class DifferentiableFunctionExtractOriginalExprBase extends @differentiable_function_extract_original_expr, ImplicitConversionExpr { - override string toString() { result = "DifferentiableFunctionExtractOriginalExpr" } + override string getPrimaryQlClass() { result = "DifferentiableFunctionExtractOriginalExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DiscardAssignmentExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DiscardAssignmentExpr.qll index 5d067a0450a..e9470dab89a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DiscardAssignmentExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DiscardAssignmentExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class DiscardAssignmentExprBase extends @discard_assignment_expr, Expr { - override string toString() { result = "DiscardAssignmentExpr" } + override string getPrimaryQlClass() { result = "DiscardAssignmentExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DotSelfExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DotSelfExpr.qll index 8ade301e4c6..8df593c6c84 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DotSelfExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DotSelfExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.IdentityExpr class DotSelfExprBase extends @dot_self_expr, IdentityExpr { - override string toString() { result = "DotSelfExpr" } + override string getPrimaryQlClass() { result = "DotSelfExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxBaseIgnoredExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxBaseIgnoredExpr.qll index aa1e4a8fd61..6a4f9148640 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxBaseIgnoredExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxBaseIgnoredExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class DotSyntaxBaseIgnoredExprBase extends @dot_syntax_base_ignored_expr, Expr { - override string toString() { result = "DotSyntaxBaseIgnoredExpr" } + override string getPrimaryQlClass() { result = "DotSyntaxBaseIgnoredExpr" } Expr getQualifier() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxCallExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxCallExpr.qll index 34eae4c9878..d5d2f53db6f 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxCallExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxCallExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.SelfApplyExpr class DotSyntaxCallExprBase extends @dot_syntax_call_expr, SelfApplyExpr { - override string toString() { result = "DotSyntaxCallExpr" } + override string getPrimaryQlClass() { result = "DotSyntaxCallExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DynamicMemberRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DynamicMemberRefExpr.qll index b7e0bcd60ef..b03992c2f89 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DynamicMemberRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DynamicMemberRefExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.DynamicLookupExpr class DynamicMemberRefExprBase extends @dynamic_member_ref_expr, DynamicLookupExpr { - override string toString() { result = "DynamicMemberRefExpr" } + override string getPrimaryQlClass() { result = "DynamicMemberRefExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DynamicSubscriptExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DynamicSubscriptExpr.qll index 9b6e61edd1e..f3ebf5db289 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DynamicSubscriptExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DynamicSubscriptExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.DynamicLookupExpr class DynamicSubscriptExprBase extends @dynamic_subscript_expr, DynamicLookupExpr { - override string toString() { result = "DynamicSubscriptExpr" } + override string getPrimaryQlClass() { result = "DynamicSubscriptExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DynamicTypeExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DynamicTypeExpr.qll index 6a2ea93be0f..651088dcdc7 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DynamicTypeExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DynamicTypeExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class DynamicTypeExprBase extends @dynamic_type_expr, Expr { - override string toString() { result = "DynamicTypeExpr" } + override string getPrimaryQlClass() { result = "DynamicTypeExpr" } Expr getBaseExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/EditorPlaceholderExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/EditorPlaceholderExpr.qll index 29018732f81..13b01ebe579 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/EditorPlaceholderExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/EditorPlaceholderExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class EditorPlaceholderExprBase extends @editor_placeholder_expr, Expr { - override string toString() { result = "EditorPlaceholderExpr" } + override string getPrimaryQlClass() { result = "EditorPlaceholderExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/EnumIsCaseExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/EnumIsCaseExpr.qll index a7ec82fb94a..7671d1fe187 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/EnumIsCaseExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/EnumIsCaseExpr.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.typerepr.TypeRepr class EnumIsCaseExprBase extends @enum_is_case_expr, Expr { - override string toString() { result = "EnumIsCaseExpr" } + override string getPrimaryQlClass() { result = "EnumIsCaseExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/ErasureExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ErasureExpr.qll index 68eeed8a6a1..8f4006a35d8 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ErasureExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ErasureExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ErasureExprBase extends @erasure_expr, ImplicitConversionExpr { - override string toString() { result = "ErasureExpr" } + override string getPrimaryQlClass() { result = "ErasureExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ErrorExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ErrorExpr.qll index b364ba3662f..c93afa1d20d 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ErrorExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ErrorExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class ErrorExprBase extends @error_expr, Expr { - override string toString() { result = "ErrorExpr" } + override string getPrimaryQlClass() { result = "ErrorExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ExistentialMetatypeToObjectExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ExistentialMetatypeToObjectExpr.qll index def4df70dc8..474ef8d876a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ExistentialMetatypeToObjectExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ExistentialMetatypeToObjectExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ExistentialMetatypeToObjectExprBase extends @existential_metatype_to_object_expr, ImplicitConversionExpr { - override string toString() { result = "ExistentialMetatypeToObjectExpr" } + override string getPrimaryQlClass() { result = "ExistentialMetatypeToObjectExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/Expr.qll b/swift/ql/lib/codeql/swift/generated/expr/Expr.qll index 77e18eecc4f..281d30988a9 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/Expr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/Expr.qll @@ -9,4 +9,6 @@ class ExprBase extends @expr, AstNode { result = x.resolve() ) } + + predicate hasType() { exists(getType()) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/FloatLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/FloatLiteralExpr.qll index d5a75020b59..d6355497331 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/FloatLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/FloatLiteralExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.NumberLiteralExpr class FloatLiteralExprBase extends @float_literal_expr, NumberLiteralExpr { - override string toString() { result = "FloatLiteralExpr" } + override string getPrimaryQlClass() { result = "FloatLiteralExpr" } string getStringValue() { float_literal_exprs(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ForceTryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ForceTryExpr.qll index 6e79e8b9d0c..077dff2565a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ForceTryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ForceTryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.AnyTryExpr class ForceTryExprBase extends @force_try_expr, AnyTryExpr { - override string toString() { result = "ForceTryExpr" } + override string getPrimaryQlClass() { result = "ForceTryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ForceValueExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ForceValueExpr.qll index 9740fce5b07..a5af8ecd64f 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ForceValueExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ForceValueExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class ForceValueExprBase extends @force_value_expr, Expr { - override string toString() { result = "ForceValueExpr" } + override string getPrimaryQlClass() { result = "ForceValueExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/ForcedCheckedCastExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ForcedCheckedCastExpr.qll index 62712596d93..cbcd27323ca 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ForcedCheckedCastExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ForcedCheckedCastExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.CheckedCastExpr class ForcedCheckedCastExprBase extends @forced_checked_cast_expr, CheckedCastExpr { - override string toString() { result = "ForcedCheckedCastExpr" } + override string getPrimaryQlClass() { result = "ForcedCheckedCastExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ForeignObjectConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ForeignObjectConversionExpr.qll index 1a04dc63a00..685cb980165 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ForeignObjectConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ForeignObjectConversionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ForeignObjectConversionExprBase extends @foreign_object_conversion_expr, ImplicitConversionExpr { - override string toString() { result = "ForeignObjectConversionExpr" } + override string getPrimaryQlClass() { result = "ForeignObjectConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/FunctionConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/FunctionConversionExpr.qll index cefeacb56c9..e996cea15c1 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/FunctionConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/FunctionConversionExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class FunctionConversionExprBase extends @function_conversion_expr, ImplicitConversionExpr { - override string toString() { result = "FunctionConversionExpr" } + override string getPrimaryQlClass() { result = "FunctionConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/IfExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/IfExpr.qll index ffba0002a9e..491d4c4b315 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/IfExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/IfExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class IfExprBase extends @if_expr, Expr { - override string toString() { result = "IfExpr" } + override string getPrimaryQlClass() { result = "IfExpr" } Expr getCondition() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/InOutExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/InOutExpr.qll index 9d8e2f89c5b..d54b02880dc 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/InOutExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/InOutExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class InOutExprBase extends @in_out_expr, Expr { - override string toString() { result = "InOutExpr" } + override string getPrimaryQlClass() { result = "InOutExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/InOutToPointerExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/InOutToPointerExpr.qll index c1c4775f0dc..19b8a0c8feb 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/InOutToPointerExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/InOutToPointerExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class InOutToPointerExprBase extends @in_out_to_pointer_expr, ImplicitConversionExpr { - override string toString() { result = "InOutToPointerExpr" } + override string getPrimaryQlClass() { result = "InOutToPointerExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/InjectIntoOptionalExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/InjectIntoOptionalExpr.qll index 98186826917..af91274bdad 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/InjectIntoOptionalExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/InjectIntoOptionalExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class InjectIntoOptionalExprBase extends @inject_into_optional_expr, ImplicitConversionExpr { - override string toString() { result = "InjectIntoOptionalExpr" } + override string getPrimaryQlClass() { result = "InjectIntoOptionalExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/IntegerLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/IntegerLiteralExpr.qll index 61e309fc20c..2599e9926ee 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/IntegerLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/IntegerLiteralExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.NumberLiteralExpr class IntegerLiteralExprBase extends @integer_literal_expr, NumberLiteralExpr { - override string toString() { result = "IntegerLiteralExpr" } + override string getPrimaryQlClass() { result = "IntegerLiteralExpr" } string getStringValue() { integer_literal_exprs(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/InterpolatedStringLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/InterpolatedStringLiteralExpr.qll index d3d5f922f45..74e9062c995 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/InterpolatedStringLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/InterpolatedStringLiteralExpr.qll @@ -5,7 +5,7 @@ import codeql.swift.elements.expr.OpaqueValueExpr import codeql.swift.elements.expr.TapExpr class InterpolatedStringLiteralExprBase extends @interpolated_string_literal_expr, LiteralExpr { - override string toString() { result = "InterpolatedStringLiteralExpr" } + override string getPrimaryQlClass() { result = "InterpolatedStringLiteralExpr" } OpaqueValueExpr getInterpolationExpr() { exists(OpaqueValueExpr x | @@ -14,6 +14,8 @@ class InterpolatedStringLiteralExprBase extends @interpolated_string_literal_exp ) } + predicate hasInterpolationExpr() { exists(getInterpolationExpr()) } + Expr getInterpolationCountExpr() { exists(Expr x | interpolated_string_literal_expr_interpolation_count_exprs(this, x) and @@ -21,6 +23,8 @@ class InterpolatedStringLiteralExprBase extends @interpolated_string_literal_exp ) } + predicate hasInterpolationCountExpr() { exists(getInterpolationCountExpr()) } + Expr getLiteralCapacityExpr() { exists(Expr x | interpolated_string_literal_expr_literal_capacity_exprs(this, x) and @@ -28,10 +32,14 @@ class InterpolatedStringLiteralExprBase extends @interpolated_string_literal_exp ) } + predicate hasLiteralCapacityExpr() { exists(getLiteralCapacityExpr()) } + TapExpr getAppendingExpr() { exists(TapExpr x | interpolated_string_literal_expr_appending_exprs(this, x) and result = x.resolve() ) } + + predicate hasAppendingExpr() { exists(getAppendingExpr()) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/IsExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/IsExpr.qll index 51af55eddb7..2591820191a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/IsExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/IsExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.CheckedCastExpr class IsExprBase extends @is_expr, CheckedCastExpr { - override string toString() { result = "IsExpr" } + override string getPrimaryQlClass() { result = "IsExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/KeyPathApplicationExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/KeyPathApplicationExpr.qll index ebf1276e749..920c4248f26 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/KeyPathApplicationExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/KeyPathApplicationExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class KeyPathApplicationExprBase extends @key_path_application_expr, Expr { - override string toString() { result = "KeyPathApplicationExpr" } + override string getPrimaryQlClass() { result = "KeyPathApplicationExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/KeyPathDotExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/KeyPathDotExpr.qll index 6e4281c7d97..ac04f37e7fe 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/KeyPathDotExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/KeyPathDotExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class KeyPathDotExprBase extends @key_path_dot_expr, Expr { - override string toString() { result = "KeyPathDotExpr" } + override string getPrimaryQlClass() { result = "KeyPathDotExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/KeyPathExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/KeyPathExpr.qll index 4801e957a8a..ccd1596a863 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/KeyPathExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/KeyPathExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class KeyPathExprBase extends @key_path_expr, Expr { - override string toString() { result = "KeyPathExpr" } + override string getPrimaryQlClass() { result = "KeyPathExpr" } Expr getParsedRoot() { exists(Expr x | @@ -11,10 +11,14 @@ class KeyPathExprBase extends @key_path_expr, Expr { ) } + predicate hasParsedRoot() { exists(getParsedRoot()) } + Expr getParsedPath() { exists(Expr x | key_path_expr_parsed_paths(this, x) and result = x.resolve() ) } + + predicate hasParsedPath() { exists(getParsedPath()) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/LazyInitializerExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/LazyInitializerExpr.qll index 8ea9da8246a..8f83e5efb42 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/LazyInitializerExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/LazyInitializerExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class LazyInitializerExprBase extends @lazy_initializer_expr, Expr { - override string toString() { result = "LazyInitializerExpr" } + override string getPrimaryQlClass() { result = "LazyInitializerExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExpr.qll index 7a7c68f3859..06e95f715fb 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class LinearFunctionExprBase extends @linear_function_expr, ImplicitConversionExpr { - override string toString() { result = "LinearFunctionExpr" } + override string getPrimaryQlClass() { result = "LinearFunctionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExtractOriginalExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExtractOriginalExpr.qll index 82fbb7f32ba..b16b4a6a800 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExtractOriginalExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExtractOriginalExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class LinearFunctionExtractOriginalExprBase extends @linear_function_extract_original_expr, ImplicitConversionExpr { - override string toString() { result = "LinearFunctionExtractOriginalExpr" } + override string getPrimaryQlClass() { result = "LinearFunctionExtractOriginalExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/LinearToDifferentiableFunctionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/LinearToDifferentiableFunctionExpr.qll index f936d79cd3e..6a9412cff81 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/LinearToDifferentiableFunctionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/LinearToDifferentiableFunctionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class LinearToDifferentiableFunctionExprBase extends @linear_to_differentiable_function_expr, ImplicitConversionExpr { - override string toString() { result = "LinearToDifferentiableFunctionExpr" } + override string getPrimaryQlClass() { result = "LinearToDifferentiableFunctionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/LoadExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/LoadExpr.qll index c2274d9b689..94e2e0419bb 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/LoadExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/LoadExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class LoadExprBase extends @load_expr, ImplicitConversionExpr { - override string toString() { result = "LoadExpr" } + override string getPrimaryQlClass() { result = "LoadExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/MagicIdentifierLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/MagicIdentifierLiteralExpr.qll index 43915a6ab5b..8518d632bad 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/MagicIdentifierLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/MagicIdentifierLiteralExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.BuiltinLiteralExpr class MagicIdentifierLiteralExprBase extends @magic_identifier_literal_expr, BuiltinLiteralExpr { - override string toString() { result = "MagicIdentifierLiteralExpr" } + override string getPrimaryQlClass() { result = "MagicIdentifierLiteralExpr" } string getKind() { magic_identifier_literal_exprs(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/MakeTemporarilyEscapableExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/MakeTemporarilyEscapableExpr.qll index 3244ef7a849..db856980eec 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/MakeTemporarilyEscapableExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/MakeTemporarilyEscapableExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.expr.OpaqueValueExpr class MakeTemporarilyEscapableExprBase extends @make_temporarily_escapable_expr, Expr { - override string toString() { result = "MakeTemporarilyEscapableExpr" } + override string getPrimaryQlClass() { result = "MakeTemporarilyEscapableExpr" } OpaqueValueExpr getEscapingClosure() { exists(OpaqueValueExpr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/MemberRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/MemberRefExpr.qll index aa453e1c705..dc8dd448bf7 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/MemberRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/MemberRefExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.expr.LookupExpr class MemberRefExprBase extends @member_ref_expr, LookupExpr { - override string toString() { result = "MemberRefExpr" } + override string getPrimaryQlClass() { result = "MemberRefExpr" } Expr getBaseExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/MetatypeConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/MetatypeConversionExpr.qll index 999afa62c9e..582ecef25ec 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/MetatypeConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/MetatypeConversionExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class MetatypeConversionExprBase extends @metatype_conversion_expr, ImplicitConversionExpr { - override string toString() { result = "MetatypeConversionExpr" } + override string getPrimaryQlClass() { result = "MetatypeConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/NilLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/NilLiteralExpr.qll index 836ce38d548..8a5ec080b28 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/NilLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/NilLiteralExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.LiteralExpr class NilLiteralExprBase extends @nil_literal_expr, LiteralExpr { - override string toString() { result = "NilLiteralExpr" } + override string getPrimaryQlClass() { result = "NilLiteralExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ObjCSelectorExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ObjCSelectorExpr.qll index 9d6cb2a924e..1d2f0e9d3a5 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ObjCSelectorExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ObjCSelectorExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.decl.AbstractFunctionDecl import codeql.swift.elements.expr.Expr class ObjCSelectorExprBase extends @obj_c_selector_expr, Expr { - override string toString() { result = "ObjCSelectorExpr" } + override string getPrimaryQlClass() { result = "ObjCSelectorExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/ObjectLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ObjectLiteralExpr.qll index 9aea71ce341..b195bd9abc4 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ObjectLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ObjectLiteralExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.LiteralExpr class ObjectLiteralExprBase extends @object_literal_expr, LiteralExpr { - override string toString() { result = "ObjectLiteralExpr" } + override string getPrimaryQlClass() { result = "ObjectLiteralExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/OneWayExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OneWayExpr.qll index 6bbd20b70b2..22cfa7726a7 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OneWayExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OneWayExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class OneWayExprBase extends @one_way_expr, Expr { - override string toString() { result = "OneWayExpr" } + override string getPrimaryQlClass() { result = "OneWayExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/OpaqueValueExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OpaqueValueExpr.qll index d88089457f1..ba56d0cf3ca 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OpaqueValueExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OpaqueValueExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class OpaqueValueExprBase extends @opaque_value_expr, Expr { - override string toString() { result = "OpaqueValueExpr" } + override string getPrimaryQlClass() { result = "OpaqueValueExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/OpenExistentialExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OpenExistentialExpr.qll index 647f258ce09..a8e8c335fd2 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OpenExistentialExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OpenExistentialExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.expr.OpaqueValueExpr class OpenExistentialExprBase extends @open_existential_expr, Expr { - override string toString() { result = "OpenExistentialExpr" } + override string getPrimaryQlClass() { result = "OpenExistentialExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/OptionalEvaluationExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OptionalEvaluationExpr.qll index df7bbbe5e27..1529d44ba6d 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OptionalEvaluationExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OptionalEvaluationExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class OptionalEvaluationExprBase extends @optional_evaluation_expr, Expr { - override string toString() { result = "OptionalEvaluationExpr" } + override string getPrimaryQlClass() { result = "OptionalEvaluationExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/OptionalTryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OptionalTryExpr.qll index 8657344eb55..b62e6fd2865 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OptionalTryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OptionalTryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.AnyTryExpr class OptionalTryExprBase extends @optional_try_expr, AnyTryExpr { - override string toString() { result = "OptionalTryExpr" } + override string getPrimaryQlClass() { result = "OptionalTryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/OtherConstructorDeclRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OtherConstructorDeclRefExpr.qll index c32da7fa5af..e4bf4398924 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OtherConstructorDeclRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OtherConstructorDeclRefExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class OtherConstructorDeclRefExprBase extends @other_constructor_decl_ref_expr, Expr { - override string toString() { result = "OtherConstructorDeclRefExpr" } + override string getPrimaryQlClass() { result = "OtherConstructorDeclRefExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/OverloadedDeclRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OverloadedDeclRefExpr.qll index bd93baa605f..3e40c2810a3 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OverloadedDeclRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OverloadedDeclRefExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.OverloadSetRefExpr class OverloadedDeclRefExprBase extends @overloaded_decl_ref_expr, OverloadSetRefExpr { - override string toString() { result = "OverloadedDeclRefExpr" } + override string getPrimaryQlClass() { result = "OverloadedDeclRefExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ParenExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ParenExpr.qll index 20ad4d97304..f6b18942e02 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ParenExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ParenExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.IdentityExpr class ParenExprBase extends @paren_expr, IdentityExpr { - override string toString() { result = "ParenExpr" } + override string getPrimaryQlClass() { result = "ParenExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/PointerToPointerExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/PointerToPointerExpr.qll index 649653c8c3e..9e292a0eb04 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/PointerToPointerExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/PointerToPointerExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class PointerToPointerExprBase extends @pointer_to_pointer_expr, ImplicitConversionExpr { - override string toString() { result = "PointerToPointerExpr" } + override string getPrimaryQlClass() { result = "PointerToPointerExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/PostfixUnaryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/PostfixUnaryExpr.qll index ce96c7bfc11..6be511150c7 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/PostfixUnaryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/PostfixUnaryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ApplyExpr class PostfixUnaryExprBase extends @postfix_unary_expr, ApplyExpr { - override string toString() { result = "PostfixUnaryExpr" } + override string getPrimaryQlClass() { result = "PostfixUnaryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/PrefixUnaryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/PrefixUnaryExpr.qll index ec122b5d785..ef31ea8acec 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/PrefixUnaryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/PrefixUnaryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ApplyExpr class PrefixUnaryExprBase extends @prefix_unary_expr, ApplyExpr { - override string toString() { result = "PrefixUnaryExpr" } + override string getPrimaryQlClass() { result = "PrefixUnaryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/PropertyWrapperValuePlaceholderExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/PropertyWrapperValuePlaceholderExpr.qll index 74ad001df53..51407fef64b 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/PropertyWrapperValuePlaceholderExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/PropertyWrapperValuePlaceholderExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class PropertyWrapperValuePlaceholderExprBase extends @property_wrapper_value_placeholder_expr, Expr { - override string toString() { result = "PropertyWrapperValuePlaceholderExpr" } + override string getPrimaryQlClass() { result = "PropertyWrapperValuePlaceholderExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ProtocolMetatypeToObjectExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ProtocolMetatypeToObjectExpr.qll index e2c4c5c25ac..33426b7ab11 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ProtocolMetatypeToObjectExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ProtocolMetatypeToObjectExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ProtocolMetatypeToObjectExprBase extends @protocol_metatype_to_object_expr, ImplicitConversionExpr { - override string toString() { result = "ProtocolMetatypeToObjectExpr" } + override string getPrimaryQlClass() { result = "ProtocolMetatypeToObjectExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/RebindSelfInConstructorExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/RebindSelfInConstructorExpr.qll index bed2006bb27..569160eb573 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/RebindSelfInConstructorExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/RebindSelfInConstructorExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.decl.VarDecl class RebindSelfInConstructorExprBase extends @rebind_self_in_constructor_expr, Expr { - override string toString() { result = "RebindSelfInConstructorExpr" } + override string getPrimaryQlClass() { result = "RebindSelfInConstructorExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/RegexLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/RegexLiteralExpr.qll index 8369264e316..00d524b7f5c 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/RegexLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/RegexLiteralExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.LiteralExpr class RegexLiteralExprBase extends @regex_literal_expr, LiteralExpr { - override string toString() { result = "RegexLiteralExpr" } + override string getPrimaryQlClass() { result = "RegexLiteralExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/SequenceExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/SequenceExpr.qll index 6de638ea809..0b1397147a1 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/SequenceExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/SequenceExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class SequenceExprBase extends @sequence_expr, Expr { - override string toString() { result = "SequenceExpr" } + override string getPrimaryQlClass() { result = "SequenceExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/StringLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/StringLiteralExpr.qll index 3f9693ba780..beb1a71c829 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/StringLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/StringLiteralExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.BuiltinLiteralExpr class StringLiteralExprBase extends @string_literal_expr, BuiltinLiteralExpr { - override string toString() { result = "StringLiteralExpr" } + override string getPrimaryQlClass() { result = "StringLiteralExpr" } string getValue() { string_literal_exprs(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/StringToPointerExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/StringToPointerExpr.qll index 0a1d64dcc6f..19553c9936a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/StringToPointerExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/StringToPointerExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class StringToPointerExprBase extends @string_to_pointer_expr, ImplicitConversionExpr { - override string toString() { result = "StringToPointerExpr" } + override string getPrimaryQlClass() { result = "StringToPointerExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/SubscriptExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/SubscriptExpr.qll index 98f201103b8..98e07ecd25b 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/SubscriptExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/SubscriptExpr.qll @@ -5,7 +5,7 @@ import codeql.swift.elements.decl.GenericContext import codeql.swift.elements.expr.LookupExpr class SubscriptExprBase extends @subscript_expr, GenericContext, LookupExpr { - override string toString() { result = "SubscriptExpr" } + override string getPrimaryQlClass() { result = "SubscriptExpr" } Expr getBaseExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/SuperRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/SuperRefExpr.qll index ec5c04c5a31..f8c6bfa740b 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/SuperRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/SuperRefExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.decl.VarDecl class SuperRefExprBase extends @super_ref_expr, Expr { - override string toString() { result = "SuperRefExpr" } + override string getPrimaryQlClass() { result = "SuperRefExpr" } VarDecl getSelf() { exists(VarDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/TapExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/TapExpr.qll index 4f537f65229..1dfc2c39bce 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/TapExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/TapExpr.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.decl.VarDecl class TapExprBase extends @tap_expr, Expr { - override string toString() { result = "TapExpr" } + override string getPrimaryQlClass() { result = "TapExpr" } Expr getSubExpr() { exists(Expr x | @@ -13,6 +13,8 @@ class TapExprBase extends @tap_expr, Expr { ) } + predicate hasSubExpr() { exists(getSubExpr()) } + VarDecl getVar() { exists(VarDecl x | tap_exprs(this, x, _) and diff --git a/swift/ql/lib/codeql/swift/generated/expr/TryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/TryExpr.qll index 06f1d82f37e..ccffde14675 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/TryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/TryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.AnyTryExpr class TryExprBase extends @try_expr, AnyTryExpr { - override string toString() { result = "TryExpr" } + override string getPrimaryQlClass() { result = "TryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/TupleElementExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/TupleElementExpr.qll index 4b3e0728ace..4f2e3b54a9c 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/TupleElementExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/TupleElementExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class TupleElementExprBase extends @tuple_element_expr, Expr { - override string toString() { result = "TupleElementExpr" } + override string getPrimaryQlClass() { result = "TupleElementExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/TupleExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/TupleExpr.qll index c3d6210299d..8024390f677 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/TupleExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/TupleExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class TupleExprBase extends @tuple_expr, Expr { - override string toString() { result = "TupleExpr" } + override string getPrimaryQlClass() { result = "TupleExpr" } Expr getElement(int index) { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/TypeExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/TypeExpr.qll index 584ad811cab..a26c599811c 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/TypeExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/TypeExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.typerepr.TypeRepr class TypeExprBase extends @type_expr, Expr { - override string toString() { result = "TypeExpr" } + override string getPrimaryQlClass() { result = "TypeExpr" } TypeRepr getTypeRepr() { exists(TypeRepr x | @@ -11,4 +11,6 @@ class TypeExprBase extends @type_expr, Expr { result = x.resolve() ) } + + predicate hasTypeRepr() { exists(getTypeRepr()) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnderlyingToOpaqueExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnderlyingToOpaqueExpr.qll index 710c357d689..9a423be665f 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnderlyingToOpaqueExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnderlyingToOpaqueExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class UnderlyingToOpaqueExprBase extends @underlying_to_opaque_expr, ImplicitConversionExpr { - override string toString() { result = "UnderlyingToOpaqueExpr" } + override string getPrimaryQlClass() { result = "UnderlyingToOpaqueExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnevaluatedInstanceExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnevaluatedInstanceExpr.qll index 4aec9923cf5..c64186f12ef 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnevaluatedInstanceExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnevaluatedInstanceExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class UnevaluatedInstanceExprBase extends @unevaluated_instance_expr, ImplicitConversionExpr { - override string toString() { result = "UnevaluatedInstanceExpr" } + override string getPrimaryQlClass() { result = "UnevaluatedInstanceExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDeclRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDeclRefExpr.qll index c3f7ed0f5b1..57a3e87d235 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDeclRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDeclRefExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class UnresolvedDeclRefExprBase extends @unresolved_decl_ref_expr, Expr { - override string toString() { result = "UnresolvedDeclRefExpr" } + override string getPrimaryQlClass() { result = "UnresolvedDeclRefExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDotExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDotExpr.qll index e77552916bc..96db0e895ce 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDotExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDotExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class UnresolvedDotExprBase extends @unresolved_dot_expr, Expr { - override string toString() { result = "UnresolvedDotExpr" } + override string getPrimaryQlClass() { result = "UnresolvedDotExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberChainResultExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberChainResultExpr.qll index b2021ed8e60..a2da6922c26 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberChainResultExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberChainResultExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.IdentityExpr class UnresolvedMemberChainResultExprBase extends @unresolved_member_chain_result_expr, IdentityExpr { - override string toString() { result = "UnresolvedMemberChainResultExpr" } + override string getPrimaryQlClass() { result = "UnresolvedMemberChainResultExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberExpr.qll index 5591495d7c4..2d5f737f294 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class UnresolvedMemberExprBase extends @unresolved_member_expr, Expr { - override string toString() { result = "UnresolvedMemberExpr" } + override string getPrimaryQlClass() { result = "UnresolvedMemberExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedPatternExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedPatternExpr.qll index ea903e736b9..5d2e88636c8 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedPatternExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedPatternExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class UnresolvedPatternExprBase extends @unresolved_pattern_expr, Expr { - override string toString() { result = "UnresolvedPatternExpr" } + override string getPrimaryQlClass() { result = "UnresolvedPatternExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedSpecializeExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedSpecializeExpr.qll index 25d0c998c88..e61e89739b1 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedSpecializeExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedSpecializeExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class UnresolvedSpecializeExprBase extends @unresolved_specialize_expr, Expr { - override string toString() { result = "UnresolvedSpecializeExpr" } + override string getPrimaryQlClass() { result = "UnresolvedSpecializeExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedTypeConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedTypeConversionExpr.qll index 4878b79873e..ac24c0426ad 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedTypeConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedTypeConversionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class UnresolvedTypeConversionExprBase extends @unresolved_type_conversion_expr, ImplicitConversionExpr { - override string toString() { result = "UnresolvedTypeConversionExpr" } + override string getPrimaryQlClass() { result = "UnresolvedTypeConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/VarargExpansionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/VarargExpansionExpr.qll index c420ef75619..6061852d7ca 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/VarargExpansionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/VarargExpansionExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class VarargExpansionExprBase extends @vararg_expansion_expr, Expr { - override string toString() { result = "VarargExpansionExpr" } + override string getPrimaryQlClass() { result = "VarargExpansionExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/AnyPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/AnyPattern.qll index 04868020580..f211968136c 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/AnyPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/AnyPattern.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.pattern.Pattern class AnyPatternBase extends @any_pattern, Pattern { - override string toString() { result = "AnyPattern" } + override string getPrimaryQlClass() { result = "AnyPattern" } } diff --git a/swift/ql/lib/codeql/swift/generated/pattern/BindingPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/BindingPattern.qll index 02446bb7729..748c71fddb8 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/BindingPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/BindingPattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class BindingPatternBase extends @binding_pattern, Pattern { - override string toString() { result = "BindingPattern" } + override string getPrimaryQlClass() { result = "BindingPattern" } Pattern getSubPattern() { exists(Pattern x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/BoolPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/BoolPattern.qll index b533d9243eb..cc4902320c4 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/BoolPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/BoolPattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class BoolPatternBase extends @bool_pattern, Pattern { - override string toString() { result = "BoolPattern" } + override string getPrimaryQlClass() { result = "BoolPattern" } boolean getValue() { bool_patterns(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/pattern/EnumElementPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/EnumElementPattern.qll index fb7ade93a8b..1f9a27886b4 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/EnumElementPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/EnumElementPattern.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.decl.EnumElementDecl import codeql.swift.elements.pattern.Pattern class EnumElementPatternBase extends @enum_element_pattern, Pattern { - override string toString() { result = "EnumElementPattern" } + override string getPrimaryQlClass() { result = "EnumElementPattern" } EnumElementDecl getElement() { exists(EnumElementDecl x | @@ -18,4 +18,6 @@ class EnumElementPatternBase extends @enum_element_pattern, Pattern { result = x.resolve() ) } + + predicate hasSubPattern() { exists(getSubPattern()) } } diff --git a/swift/ql/lib/codeql/swift/generated/pattern/ExprPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/ExprPattern.qll index 2114614f348..49946d7bc59 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/ExprPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/ExprPattern.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.pattern.Pattern class ExprPatternBase extends @expr_pattern, Pattern { - override string toString() { result = "ExprPattern" } + override string getPrimaryQlClass() { result = "ExprPattern" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/IsPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/IsPattern.qll index dda92156f27..d491a253c28 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/IsPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/IsPattern.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.pattern.Pattern import codeql.swift.elements.typerepr.TypeRepr class IsPatternBase extends @is_pattern, Pattern { - override string toString() { result = "IsPattern" } + override string getPrimaryQlClass() { result = "IsPattern" } TypeRepr getCastTypeRepr() { exists(TypeRepr x | @@ -12,10 +12,14 @@ class IsPatternBase extends @is_pattern, Pattern { ) } + predicate hasCastTypeRepr() { exists(getCastTypeRepr()) } + Pattern getSubPattern() { exists(Pattern x | is_pattern_sub_patterns(this, x) and result = x.resolve() ) } + + predicate hasSubPattern() { exists(getSubPattern()) } } diff --git a/swift/ql/lib/codeql/swift/generated/pattern/NamedPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/NamedPattern.qll index 833474b11e9..d7d43f0b738 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/NamedPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/NamedPattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class NamedPatternBase extends @named_pattern, Pattern { - override string toString() { result = "NamedPattern" } + override string getPrimaryQlClass() { result = "NamedPattern" } string getName() { named_patterns(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/pattern/OptionalSomePattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/OptionalSomePattern.qll index bd205e2fe1d..0ca8700175b 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/OptionalSomePattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/OptionalSomePattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class OptionalSomePatternBase extends @optional_some_pattern, Pattern { - override string toString() { result = "OptionalSomePattern" } + override string getPrimaryQlClass() { result = "OptionalSomePattern" } Pattern getSubPattern() { exists(Pattern x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/ParenPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/ParenPattern.qll index f3ddab4b9dd..815df89026c 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/ParenPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/ParenPattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class ParenPatternBase extends @paren_pattern, Pattern { - override string toString() { result = "ParenPattern" } + override string getPrimaryQlClass() { result = "ParenPattern" } Pattern getSubPattern() { exists(Pattern x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/TuplePattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/TuplePattern.qll index f1de477cc55..86aad12c87d 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/TuplePattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/TuplePattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class TuplePatternBase extends @tuple_pattern, Pattern { - override string toString() { result = "TuplePattern" } + override string getPrimaryQlClass() { result = "TuplePattern" } Pattern getElement(int index) { exists(Pattern x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/TypedPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/TypedPattern.qll index e86ca301fdc..8eeb3f95744 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/TypedPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/TypedPattern.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.pattern.Pattern import codeql.swift.elements.typerepr.TypeRepr class TypedPatternBase extends @typed_pattern, Pattern { - override string toString() { result = "TypedPattern" } + override string getPrimaryQlClass() { result = "TypedPattern" } Pattern getSubPattern() { exists(Pattern x | @@ -18,4 +18,6 @@ class TypedPatternBase extends @typed_pattern, Pattern { result = x.resolve() ) } + + predicate hasTypeRepr() { exists(getTypeRepr()) } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/BraceStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/BraceStmt.qll index 6515d0ac26a..4195c11a226 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/BraceStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/BraceStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.AstNode import codeql.swift.elements.stmt.Stmt class BraceStmtBase extends @brace_stmt, Stmt { - override string toString() { result = "BraceStmt" } + override string getPrimaryQlClass() { result = "BraceStmt" } AstNode getElement(int index) { exists(AstNode x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/BreakStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/BreakStmt.qll index d0e0a84c59d..34e6913e79d 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/BreakStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/BreakStmt.qll @@ -2,14 +2,18 @@ import codeql.swift.elements.stmt.Stmt class BreakStmtBase extends @break_stmt, Stmt { - override string toString() { result = "BreakStmt" } + override string getPrimaryQlClass() { result = "BreakStmt" } string getTargetName() { break_stmt_target_names(this, result) } + predicate hasTargetName() { exists(getTargetName()) } + Stmt getTarget() { exists(Stmt x | break_stmt_targets(this, x) and result = x.resolve() ) } + + predicate hasTarget() { exists(getTarget()) } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/CaseLabelItem.qll b/swift/ql/lib/codeql/swift/generated/stmt/CaseLabelItem.qll index f5f9680ed6c..9f51f7da38f 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/CaseLabelItem.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/CaseLabelItem.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.pattern.Pattern class CaseLabelItemBase extends @case_label_item, AstNode { - override string toString() { result = "CaseLabelItem" } + override string getPrimaryQlClass() { result = "CaseLabelItem" } Pattern getPattern() { exists(Pattern x | @@ -19,4 +19,6 @@ class CaseLabelItemBase extends @case_label_item, AstNode { result = x.resolve() ) } + + predicate hasGuard() { exists(getGuard()) } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/CaseStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/CaseStmt.qll index 030a0236c07..738fca6ae43 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/CaseStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/CaseStmt.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.stmt.Stmt import codeql.swift.elements.decl.VarDecl class CaseStmtBase extends @case_stmt, Stmt { - override string toString() { result = "CaseStmt" } + override string getPrimaryQlClass() { result = "CaseStmt" } Stmt getBody() { exists(Stmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/ConditionElement.qll b/swift/ql/lib/codeql/swift/generated/stmt/ConditionElement.qll index c704c8f2710..efde6e9a5e7 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/ConditionElement.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/ConditionElement.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.Locatable import codeql.swift.elements.pattern.Pattern class ConditionElementBase extends @condition_element, Locatable { - override string toString() { result = "ConditionElement" } + override string getPrimaryQlClass() { result = "ConditionElement" } Expr getBoolean() { exists(Expr x | @@ -13,6 +13,8 @@ class ConditionElementBase extends @condition_element, Locatable { ) } + predicate hasBoolean() { exists(getBoolean()) } + Pattern getPattern() { exists(Pattern x | condition_element_patterns(this, x) and @@ -20,10 +22,14 @@ class ConditionElementBase extends @condition_element, Locatable { ) } + predicate hasPattern() { exists(getPattern()) } + Expr getInitializer() { exists(Expr x | condition_element_initializers(this, x) and result = x.resolve() ) } + + predicate hasInitializer() { exists(getInitializer()) } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/ContinueStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/ContinueStmt.qll index 0c616fc659a..1c03ce6521b 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/ContinueStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/ContinueStmt.qll @@ -2,14 +2,18 @@ import codeql.swift.elements.stmt.Stmt class ContinueStmtBase extends @continue_stmt, Stmt { - override string toString() { result = "ContinueStmt" } + override string getPrimaryQlClass() { result = "ContinueStmt" } string getTargetName() { continue_stmt_target_names(this, result) } + predicate hasTargetName() { exists(getTargetName()) } + Stmt getTarget() { exists(Stmt x | continue_stmt_targets(this, x) and result = x.resolve() ) } + + predicate hasTarget() { exists(getTarget()) } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/DeferStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/DeferStmt.qll index cbf703972f5..910b18c233d 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/DeferStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/DeferStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.BraceStmt import codeql.swift.elements.stmt.Stmt class DeferStmtBase extends @defer_stmt, Stmt { - override string toString() { result = "DeferStmt" } + override string getPrimaryQlClass() { result = "DeferStmt" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/DoCatchStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/DoCatchStmt.qll index 92d2664af0d..56f8224b98a 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/DoCatchStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/DoCatchStmt.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.stmt.LabeledStmt import codeql.swift.elements.stmt.Stmt class DoCatchStmtBase extends @do_catch_stmt, LabeledStmt { - override string toString() { result = "DoCatchStmt" } + override string getPrimaryQlClass() { result = "DoCatchStmt" } Stmt getBody() { exists(Stmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/DoStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/DoStmt.qll index d3b3964c13f..7cfa724b1e6 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/DoStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/DoStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.BraceStmt import codeql.swift.elements.stmt.LabeledStmt class DoStmtBase extends @do_stmt, LabeledStmt { - override string toString() { result = "DoStmt" } + override string getPrimaryQlClass() { result = "DoStmt" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/FailStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/FailStmt.qll index b045005cb7f..dc5ce43c903 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/FailStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/FailStmt.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.stmt.Stmt class FailStmtBase extends @fail_stmt, Stmt { - override string toString() { result = "FailStmt" } + override string getPrimaryQlClass() { result = "FailStmt" } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/FallthroughStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/FallthroughStmt.qll index beac80ab918..1adfbbd972f 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/FallthroughStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/FallthroughStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.CaseStmt import codeql.swift.elements.stmt.Stmt class FallthroughStmtBase extends @fallthrough_stmt, Stmt { - override string toString() { result = "FallthroughStmt" } + override string getPrimaryQlClass() { result = "FallthroughStmt" } CaseStmt getFallthroughSource() { exists(CaseStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/ForEachStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/ForEachStmt.qll index b0a1e357d57..ad1fb14ee8e 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/ForEachStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/ForEachStmt.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.stmt.LabeledStmt class ForEachStmtBase extends @for_each_stmt, LabeledStmt { - override string toString() { result = "ForEachStmt" } + override string getPrimaryQlClass() { result = "ForEachStmt" } BraceStmt getBody() { exists(BraceStmt x | @@ -26,4 +26,6 @@ class ForEachStmtBase extends @for_each_stmt, LabeledStmt { result = x.resolve() ) } + + predicate hasWhere() { exists(getWhere()) } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/GuardStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/GuardStmt.qll index a22da861807..933bd56b2df 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/GuardStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/GuardStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.BraceStmt import codeql.swift.elements.stmt.LabeledConditionalStmt class GuardStmtBase extends @guard_stmt, LabeledConditionalStmt { - override string toString() { result = "GuardStmt" } + override string getPrimaryQlClass() { result = "GuardStmt" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/IfStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/IfStmt.qll index e9030626766..381c2cc9097 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/IfStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/IfStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.LabeledConditionalStmt import codeql.swift.elements.stmt.Stmt class IfStmtBase extends @if_stmt, LabeledConditionalStmt { - override string toString() { result = "IfStmt" } + override string getPrimaryQlClass() { result = "IfStmt" } Stmt getThen() { exists(Stmt x | @@ -18,4 +18,6 @@ class IfStmtBase extends @if_stmt, LabeledConditionalStmt { result = x.resolve() ) } + + predicate hasElse() { exists(getElse()) } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/LabeledStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/LabeledStmt.qll index 6fcd47930dc..98374c9a5d2 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/LabeledStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/LabeledStmt.qll @@ -3,4 +3,6 @@ import codeql.swift.elements.stmt.Stmt class LabeledStmtBase extends @labeled_stmt, Stmt { string getLabel() { labeled_stmt_labels(this, result) } + + predicate hasLabel() { exists(getLabel()) } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/PoundAssertStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/PoundAssertStmt.qll index ccce691d3d7..9538899c285 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/PoundAssertStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/PoundAssertStmt.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.stmt.Stmt class PoundAssertStmtBase extends @pound_assert_stmt, Stmt { - override string toString() { result = "PoundAssertStmt" } + override string getPrimaryQlClass() { result = "PoundAssertStmt" } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/RepeatWhileStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/RepeatWhileStmt.qll index 291c0723ecf..688847947c8 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/RepeatWhileStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/RepeatWhileStmt.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.stmt.LabeledStmt import codeql.swift.elements.stmt.Stmt class RepeatWhileStmtBase extends @repeat_while_stmt, LabeledStmt { - override string toString() { result = "RepeatWhileStmt" } + override string getPrimaryQlClass() { result = "RepeatWhileStmt" } Expr getCondition() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/ReturnStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/ReturnStmt.qll index 4bde758e9e8..167d1795d19 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/ReturnStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/ReturnStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.stmt.Stmt class ReturnStmtBase extends @return_stmt, Stmt { - override string toString() { result = "ReturnStmt" } + override string getPrimaryQlClass() { result = "ReturnStmt" } Expr getResult() { exists(Expr x | @@ -11,4 +11,6 @@ class ReturnStmtBase extends @return_stmt, Stmt { result = x.resolve() ) } + + predicate hasResult() { exists(getResult()) } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/StmtCondition.qll b/swift/ql/lib/codeql/swift/generated/stmt/StmtCondition.qll index 348cd6c564b..19e0614f192 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/StmtCondition.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/StmtCondition.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.AstNode import codeql.swift.elements.stmt.ConditionElement class StmtConditionBase extends @stmt_condition, AstNode { - override string toString() { result = "StmtCondition" } + override string getPrimaryQlClass() { result = "StmtCondition" } ConditionElement getElement(int index) { exists(ConditionElement x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/SwitchStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/SwitchStmt.qll index f137d7bd228..9bc1223aa59 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/SwitchStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/SwitchStmt.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.stmt.LabeledStmt class SwitchStmtBase extends @switch_stmt, LabeledStmt { - override string toString() { result = "SwitchStmt" } + override string getPrimaryQlClass() { result = "SwitchStmt" } Expr getExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/ThrowStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/ThrowStmt.qll index 5f724780bd1..5d542ced5b0 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/ThrowStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/ThrowStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.stmt.Stmt class ThrowStmtBase extends @throw_stmt, Stmt { - override string toString() { result = "ThrowStmt" } + override string getPrimaryQlClass() { result = "ThrowStmt" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/WhileStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/WhileStmt.qll index 23a69ccfa36..e4a197593d6 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/WhileStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/WhileStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.LabeledConditionalStmt import codeql.swift.elements.stmt.Stmt class WhileStmtBase extends @while_stmt, LabeledConditionalStmt { - override string toString() { result = "WhileStmt" } + override string getPrimaryQlClass() { result = "WhileStmt" } Stmt getBody() { exists(Stmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/YieldStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/YieldStmt.qll index 6c94f2936f5..544fdd9751e 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/YieldStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/YieldStmt.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.stmt.Stmt class YieldStmtBase extends @yield_stmt, Stmt { - override string toString() { result = "YieldStmt" } + override string getPrimaryQlClass() { result = "YieldStmt" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/AnyGenericType.qll b/swift/ql/lib/codeql/swift/generated/type/AnyGenericType.qll index b366aac7496..41659bd5f08 100644 --- a/swift/ql/lib/codeql/swift/generated/type/AnyGenericType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/AnyGenericType.qll @@ -10,6 +10,8 @@ class AnyGenericTypeBase extends @any_generic_type, Type { ) } + predicate hasParent() { exists(getParent()) } + Decl getDeclaration() { exists(Decl x | any_generic_types(this, x) and diff --git a/swift/ql/lib/codeql/swift/generated/type/ArraySliceType.qll b/swift/ql/lib/codeql/swift/generated/type/ArraySliceType.qll index f72995035e0..2b029e0f741 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ArraySliceType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ArraySliceType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.UnarySyntaxSugarType class ArraySliceTypeBase extends @array_slice_type, UnarySyntaxSugarType { - override string toString() { result = "ArraySliceType" } + override string getPrimaryQlClass() { result = "ArraySliceType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BoundGenericClassType.qll b/swift/ql/lib/codeql/swift/generated/type/BoundGenericClassType.qll index 10838dc3cd4..d7bf09fddd2 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BoundGenericClassType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BoundGenericClassType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BoundGenericType class BoundGenericClassTypeBase extends @bound_generic_class_type, BoundGenericType { - override string toString() { result = "BoundGenericClassType" } + override string getPrimaryQlClass() { result = "BoundGenericClassType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BoundGenericEnumType.qll b/swift/ql/lib/codeql/swift/generated/type/BoundGenericEnumType.qll index fb47e1e1012..e73f964c395 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BoundGenericEnumType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BoundGenericEnumType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BoundGenericType class BoundGenericEnumTypeBase extends @bound_generic_enum_type, BoundGenericType { - override string toString() { result = "BoundGenericEnumType" } + override string getPrimaryQlClass() { result = "BoundGenericEnumType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BoundGenericStructType.qll b/swift/ql/lib/codeql/swift/generated/type/BoundGenericStructType.qll index 9c52908a7a0..1b7a82b165a 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BoundGenericStructType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BoundGenericStructType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BoundGenericType class BoundGenericStructTypeBase extends @bound_generic_struct_type, BoundGenericType { - override string toString() { result = "BoundGenericStructType" } + override string getPrimaryQlClass() { result = "BoundGenericStructType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinBridgeObjectType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinBridgeObjectType.qll index c39b9d3c0e0..d9d99ea7621 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinBridgeObjectType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinBridgeObjectType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinBridgeObjectTypeBase extends @builtin_bridge_object_type, BuiltinType { - override string toString() { result = "BuiltinBridgeObjectType" } + override string getPrimaryQlClass() { result = "BuiltinBridgeObjectType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinDefaultActorStorageType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinDefaultActorStorageType.qll index be8f5527ab0..88766c8a91b 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinDefaultActorStorageType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinDefaultActorStorageType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinDefaultActorStorageTypeBase extends @builtin_default_actor_storage_type, BuiltinType { - override string toString() { result = "BuiltinDefaultActorStorageType" } + override string getPrimaryQlClass() { result = "BuiltinDefaultActorStorageType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinExecutorType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinExecutorType.qll index 13c3c8a672a..fb49989bf5e 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinExecutorType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinExecutorType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinExecutorTypeBase extends @builtin_executor_type, BuiltinType { - override string toString() { result = "BuiltinExecutorType" } + override string getPrimaryQlClass() { result = "BuiltinExecutorType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinFloatType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinFloatType.qll index 03395bb5d3a..32b1244b0ef 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinFloatType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinFloatType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinFloatTypeBase extends @builtin_float_type, BuiltinType { - override string toString() { result = "BuiltinFloatType" } + override string getPrimaryQlClass() { result = "BuiltinFloatType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerLiteralType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerLiteralType.qll index e4eeb5f574c..2e61b1008cf 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerLiteralType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerLiteralType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyBuiltinIntegerType class BuiltinIntegerLiteralTypeBase extends @builtin_integer_literal_type, AnyBuiltinIntegerType { - override string toString() { result = "BuiltinIntegerLiteralType" } + override string getPrimaryQlClass() { result = "BuiltinIntegerLiteralType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerType.qll index 05d0adf5ac2..eaeb8656e7d 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyBuiltinIntegerType class BuiltinIntegerTypeBase extends @builtin_integer_type, AnyBuiltinIntegerType { - override string toString() { result = "BuiltinIntegerType" } + override string getPrimaryQlClass() { result = "BuiltinIntegerType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinJobType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinJobType.qll index ec226839e5e..f2e8fc76c73 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinJobType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinJobType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinJobTypeBase extends @builtin_job_type, BuiltinType { - override string toString() { result = "BuiltinJobType" } + override string getPrimaryQlClass() { result = "BuiltinJobType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinNativeObjectType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinNativeObjectType.qll index 6a8f75fe582..6382b94bc1b 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinNativeObjectType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinNativeObjectType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinNativeObjectTypeBase extends @builtin_native_object_type, BuiltinType { - override string toString() { result = "BuiltinNativeObjectType" } + override string getPrimaryQlClass() { result = "BuiltinNativeObjectType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinRawPointerType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinRawPointerType.qll index ebc8e11fdd0..f56d5921d30 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinRawPointerType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinRawPointerType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinRawPointerTypeBase extends @builtin_raw_pointer_type, BuiltinType { - override string toString() { result = "BuiltinRawPointerType" } + override string getPrimaryQlClass() { result = "BuiltinRawPointerType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinRawUnsafeContinuationType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinRawUnsafeContinuationType.qll index 82d6bdb8e05..d9edb49d4b3 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinRawUnsafeContinuationType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinRawUnsafeContinuationType.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinRawUnsafeContinuationTypeBase extends @builtin_raw_unsafe_continuation_type, BuiltinType { - override string toString() { result = "BuiltinRawUnsafeContinuationType" } + override string getPrimaryQlClass() { result = "BuiltinRawUnsafeContinuationType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinUnsafeValueBufferType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinUnsafeValueBufferType.qll index dcf5ad2cc99..02e200cb39e 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinUnsafeValueBufferType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinUnsafeValueBufferType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinUnsafeValueBufferTypeBase extends @builtin_unsafe_value_buffer_type, BuiltinType { - override string toString() { result = "BuiltinUnsafeValueBufferType" } + override string getPrimaryQlClass() { result = "BuiltinUnsafeValueBufferType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinVectorType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinVectorType.qll index 2a8e43f4d8f..3c1b612470f 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinVectorType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinVectorType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinVectorTypeBase extends @builtin_vector_type, BuiltinType { - override string toString() { result = "BuiltinVectorType" } + override string getPrimaryQlClass() { result = "BuiltinVectorType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ClassType.qll b/swift/ql/lib/codeql/swift/generated/type/ClassType.qll index 379c8a71aef..5fbb1ea181c 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ClassType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ClassType.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.decl.ClassDecl import codeql.swift.elements.type.NominalType class ClassTypeBase extends @class_type, NominalType { - override string toString() { result = "ClassType" } + override string getPrimaryQlClass() { result = "ClassType" } ClassDecl getDecl() { exists(ClassDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/type/DependentMemberType.qll b/swift/ql/lib/codeql/swift/generated/type/DependentMemberType.qll index 7a70d09dbef..9724322349c 100644 --- a/swift/ql/lib/codeql/swift/generated/type/DependentMemberType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/DependentMemberType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class DependentMemberTypeBase extends @dependent_member_type, Type { - override string toString() { result = "DependentMemberType" } + override string getPrimaryQlClass() { result = "DependentMemberType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/DictionaryType.qll b/swift/ql/lib/codeql/swift/generated/type/DictionaryType.qll index 30bd28f99c1..8c469221d6d 100644 --- a/swift/ql/lib/codeql/swift/generated/type/DictionaryType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/DictionaryType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.SyntaxSugarType class DictionaryTypeBase extends @dictionary_type, SyntaxSugarType { - override string toString() { result = "DictionaryType" } + override string getPrimaryQlClass() { result = "DictionaryType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/DynamicSelfType.qll b/swift/ql/lib/codeql/swift/generated/type/DynamicSelfType.qll index 5b1913db7c7..cc1bd77d0ca 100644 --- a/swift/ql/lib/codeql/swift/generated/type/DynamicSelfType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/DynamicSelfType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class DynamicSelfTypeBase extends @dynamic_self_type, Type { - override string toString() { result = "DynamicSelfType" } + override string getPrimaryQlClass() { result = "DynamicSelfType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/EnumType.qll b/swift/ql/lib/codeql/swift/generated/type/EnumType.qll index 5fd3d90acb4..67b35b77327 100644 --- a/swift/ql/lib/codeql/swift/generated/type/EnumType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/EnumType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.NominalType class EnumTypeBase extends @enum_type, NominalType { - override string toString() { result = "EnumType" } + override string getPrimaryQlClass() { result = "EnumType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ErrorType.qll b/swift/ql/lib/codeql/swift/generated/type/ErrorType.qll index 2d65d938f86..9ca5121caba 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ErrorType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ErrorType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class ErrorTypeBase extends @error_type, Type { - override string toString() { result = "ErrorType" } + override string getPrimaryQlClass() { result = "ErrorType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ExistentialMetatypeType.qll b/swift/ql/lib/codeql/swift/generated/type/ExistentialMetatypeType.qll index b84efeb003a..f833a4ecb9c 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ExistentialMetatypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ExistentialMetatypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyMetatypeType class ExistentialMetatypeTypeBase extends @existential_metatype_type, AnyMetatypeType { - override string toString() { result = "ExistentialMetatypeType" } + override string getPrimaryQlClass() { result = "ExistentialMetatypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ExistentialType.qll b/swift/ql/lib/codeql/swift/generated/type/ExistentialType.qll index 5f4ae535fdb..349c5f2cd64 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ExistentialType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ExistentialType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class ExistentialTypeBase extends @existential_type, Type { - override string toString() { result = "ExistentialType" } + override string getPrimaryQlClass() { result = "ExistentialType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/FunctionType.qll b/swift/ql/lib/codeql/swift/generated/type/FunctionType.qll index c2550ea442c..e5bd2a38e61 100644 --- a/swift/ql/lib/codeql/swift/generated/type/FunctionType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/FunctionType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyFunctionType class FunctionTypeBase extends @function_type, AnyFunctionType { - override string toString() { result = "FunctionType" } + override string getPrimaryQlClass() { result = "FunctionType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/GenericFunctionType.qll b/swift/ql/lib/codeql/swift/generated/type/GenericFunctionType.qll index cc3395146be..2094eabead8 100644 --- a/swift/ql/lib/codeql/swift/generated/type/GenericFunctionType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/GenericFunctionType.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.type.AnyFunctionType import codeql.swift.elements.type.GenericTypeParamType class GenericFunctionTypeBase extends @generic_function_type, AnyFunctionType { - override string toString() { result = "GenericFunctionType" } + override string getPrimaryQlClass() { result = "GenericFunctionType" } GenericTypeParamType getGenericParam(int index) { exists(GenericTypeParamType x | diff --git a/swift/ql/lib/codeql/swift/generated/type/GenericTypeParamType.qll b/swift/ql/lib/codeql/swift/generated/type/GenericTypeParamType.qll index de0a5c7c596..848b6ca728e 100644 --- a/swift/ql/lib/codeql/swift/generated/type/GenericTypeParamType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/GenericTypeParamType.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.type.SubstitutableType class GenericTypeParamTypeBase extends @generic_type_param_type, SubstitutableType { - override string toString() { result = "GenericTypeParamType" } + override string getPrimaryQlClass() { result = "GenericTypeParamType" } string getName() { generic_type_param_types(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/type/InOutType.qll b/swift/ql/lib/codeql/swift/generated/type/InOutType.qll index 17ff1407de2..dc0ed86c0f6 100644 --- a/swift/ql/lib/codeql/swift/generated/type/InOutType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/InOutType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class InOutTypeBase extends @in_out_type, Type { - override string toString() { result = "InOutType" } + override string getPrimaryQlClass() { result = "InOutType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/LValueType.qll b/swift/ql/lib/codeql/swift/generated/type/LValueType.qll index a7ede84558f..abba3937ddc 100644 --- a/swift/ql/lib/codeql/swift/generated/type/LValueType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/LValueType.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.type.Type class LValueTypeBase extends @l_value_type, Type { - override string toString() { result = "LValueType" } + override string getPrimaryQlClass() { result = "LValueType" } Type getObjectType() { exists(Type x | diff --git a/swift/ql/lib/codeql/swift/generated/type/MetatypeType.qll b/swift/ql/lib/codeql/swift/generated/type/MetatypeType.qll index 376fa39728b..73ecd90e57d 100644 --- a/swift/ql/lib/codeql/swift/generated/type/MetatypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/MetatypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyMetatypeType class MetatypeTypeBase extends @metatype_type, AnyMetatypeType { - override string toString() { result = "MetatypeType" } + override string getPrimaryQlClass() { result = "MetatypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ModuleType.qll b/swift/ql/lib/codeql/swift/generated/type/ModuleType.qll index a73ffdbf887..d3930e98f16 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ModuleType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ModuleType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class ModuleTypeBase extends @module_type, Type { - override string toString() { result = "ModuleType" } + override string getPrimaryQlClass() { result = "ModuleType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/NestedArchetypeType.qll b/swift/ql/lib/codeql/swift/generated/type/NestedArchetypeType.qll index 60a4b419321..dcbc5e37382 100644 --- a/swift/ql/lib/codeql/swift/generated/type/NestedArchetypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/NestedArchetypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ArchetypeType class NestedArchetypeTypeBase extends @nested_archetype_type, ArchetypeType { - override string toString() { result = "NestedArchetypeType" } + override string getPrimaryQlClass() { result = "NestedArchetypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/OpaqueTypeArchetypeType.qll b/swift/ql/lib/codeql/swift/generated/type/OpaqueTypeArchetypeType.qll index 4da709633ae..a891f5fa01c 100644 --- a/swift/ql/lib/codeql/swift/generated/type/OpaqueTypeArchetypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/OpaqueTypeArchetypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ArchetypeType class OpaqueTypeArchetypeTypeBase extends @opaque_type_archetype_type, ArchetypeType { - override string toString() { result = "OpaqueTypeArchetypeType" } + override string getPrimaryQlClass() { result = "OpaqueTypeArchetypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/OpenedArchetypeType.qll b/swift/ql/lib/codeql/swift/generated/type/OpenedArchetypeType.qll index 7fb6feee0df..8060c387cb3 100644 --- a/swift/ql/lib/codeql/swift/generated/type/OpenedArchetypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/OpenedArchetypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ArchetypeType class OpenedArchetypeTypeBase extends @opened_archetype_type, ArchetypeType { - override string toString() { result = "OpenedArchetypeType" } + override string getPrimaryQlClass() { result = "OpenedArchetypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/OptionalType.qll b/swift/ql/lib/codeql/swift/generated/type/OptionalType.qll index d30a2f46b3f..6a9002753ae 100644 --- a/swift/ql/lib/codeql/swift/generated/type/OptionalType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/OptionalType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.UnarySyntaxSugarType class OptionalTypeBase extends @optional_type, UnarySyntaxSugarType { - override string toString() { result = "OptionalType" } + override string getPrimaryQlClass() { result = "OptionalType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ParenType.qll b/swift/ql/lib/codeql/swift/generated/type/ParenType.qll index e0d49f5ff10..a1124af7033 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ParenType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ParenType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.SugarType class ParenTypeBase extends @paren_type, SugarType { - override string toString() { result = "ParenType" } + override string getPrimaryQlClass() { result = "ParenType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/PlaceholderType.qll b/swift/ql/lib/codeql/swift/generated/type/PlaceholderType.qll index f5534efe9cd..7f5e292d326 100644 --- a/swift/ql/lib/codeql/swift/generated/type/PlaceholderType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/PlaceholderType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class PlaceholderTypeBase extends @placeholder_type, Type { - override string toString() { result = "PlaceholderType" } + override string getPrimaryQlClass() { result = "PlaceholderType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/PrimaryArchetypeType.qll b/swift/ql/lib/codeql/swift/generated/type/PrimaryArchetypeType.qll index 0e71f5aca0e..2790cad235c 100644 --- a/swift/ql/lib/codeql/swift/generated/type/PrimaryArchetypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/PrimaryArchetypeType.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.type.ArchetypeType import codeql.swift.elements.type.GenericTypeParamType class PrimaryArchetypeTypeBase extends @primary_archetype_type, ArchetypeType { - override string toString() { result = "PrimaryArchetypeType" } + override string getPrimaryQlClass() { result = "PrimaryArchetypeType" } GenericTypeParamType getInterfaceType() { exists(GenericTypeParamType x | diff --git a/swift/ql/lib/codeql/swift/generated/type/ProtocolCompositionType.qll b/swift/ql/lib/codeql/swift/generated/type/ProtocolCompositionType.qll index 9bb043938aa..05f1e2217b2 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ProtocolCompositionType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ProtocolCompositionType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class ProtocolCompositionTypeBase extends @protocol_composition_type, Type { - override string toString() { result = "ProtocolCompositionType" } + override string getPrimaryQlClass() { result = "ProtocolCompositionType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ProtocolType.qll b/swift/ql/lib/codeql/swift/generated/type/ProtocolType.qll index f30992b60bc..1550e83b488 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ProtocolType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ProtocolType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.NominalType class ProtocolTypeBase extends @protocol_type, NominalType { - override string toString() { result = "ProtocolType" } + override string getPrimaryQlClass() { result = "ProtocolType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/SequenceArchetypeType.qll b/swift/ql/lib/codeql/swift/generated/type/SequenceArchetypeType.qll index 7b1b753d046..289a2e353a9 100644 --- a/swift/ql/lib/codeql/swift/generated/type/SequenceArchetypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/SequenceArchetypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ArchetypeType class SequenceArchetypeTypeBase extends @sequence_archetype_type, ArchetypeType { - override string toString() { result = "SequenceArchetypeType" } + override string getPrimaryQlClass() { result = "SequenceArchetypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/SilBlockStorageType.qll b/swift/ql/lib/codeql/swift/generated/type/SilBlockStorageType.qll index 3e76470b7db..2743a47444d 100644 --- a/swift/ql/lib/codeql/swift/generated/type/SilBlockStorageType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/SilBlockStorageType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class SilBlockStorageTypeBase extends @sil_block_storage_type, Type { - override string toString() { result = "SilBlockStorageType" } + override string getPrimaryQlClass() { result = "SilBlockStorageType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/SilBoxType.qll b/swift/ql/lib/codeql/swift/generated/type/SilBoxType.qll index c9372a2189e..26d6ef84f3b 100644 --- a/swift/ql/lib/codeql/swift/generated/type/SilBoxType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/SilBoxType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class SilBoxTypeBase extends @sil_box_type, Type { - override string toString() { result = "SilBoxType" } + override string getPrimaryQlClass() { result = "SilBoxType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/SilFunctionType.qll b/swift/ql/lib/codeql/swift/generated/type/SilFunctionType.qll index 06095435896..2299a4ea753 100644 --- a/swift/ql/lib/codeql/swift/generated/type/SilFunctionType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/SilFunctionType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class SilFunctionTypeBase extends @sil_function_type, Type { - override string toString() { result = "SilFunctionType" } + override string getPrimaryQlClass() { result = "SilFunctionType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/SilTokenType.qll b/swift/ql/lib/codeql/swift/generated/type/SilTokenType.qll index 0214692a3b0..ed988b86014 100644 --- a/swift/ql/lib/codeql/swift/generated/type/SilTokenType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/SilTokenType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class SilTokenTypeBase extends @sil_token_type, Type { - override string toString() { result = "SilTokenType" } + override string getPrimaryQlClass() { result = "SilTokenType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/StructType.qll b/swift/ql/lib/codeql/swift/generated/type/StructType.qll index 4a78562f4a4..3d23e210c59 100644 --- a/swift/ql/lib/codeql/swift/generated/type/StructType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/StructType.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.type.NominalType import codeql.swift.elements.decl.StructDecl class StructTypeBase extends @struct_type, NominalType { - override string toString() { result = "StructType" } + override string getPrimaryQlClass() { result = "StructType" } StructDecl getDecl() { exists(StructDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/type/TupleType.qll b/swift/ql/lib/codeql/swift/generated/type/TupleType.qll index 91adaf4038f..ba5b4c50e2c 100644 --- a/swift/ql/lib/codeql/swift/generated/type/TupleType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/TupleType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class TupleTypeBase extends @tuple_type, Type { - override string toString() { result = "TupleType" } + override string getPrimaryQlClass() { result = "TupleType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/TypeAliasType.qll b/swift/ql/lib/codeql/swift/generated/type/TypeAliasType.qll index 6807dc7b2a3..e5a5d8d5aba 100644 --- a/swift/ql/lib/codeql/swift/generated/type/TypeAliasType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/TypeAliasType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.SugarType class TypeAliasTypeBase extends @type_alias_type, SugarType { - override string toString() { result = "TypeAliasType" } + override string getPrimaryQlClass() { result = "TypeAliasType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/TypeVariableType.qll b/swift/ql/lib/codeql/swift/generated/type/TypeVariableType.qll index 85b8fb8c908..0714a59f039 100644 --- a/swift/ql/lib/codeql/swift/generated/type/TypeVariableType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/TypeVariableType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class TypeVariableTypeBase extends @type_variable_type, Type { - override string toString() { result = "TypeVariableType" } + override string getPrimaryQlClass() { result = "TypeVariableType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/UnboundGenericType.qll b/swift/ql/lib/codeql/swift/generated/type/UnboundGenericType.qll index e5cc43f760e..4d64e72720f 100644 --- a/swift/ql/lib/codeql/swift/generated/type/UnboundGenericType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/UnboundGenericType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyGenericType class UnboundGenericTypeBase extends @unbound_generic_type, AnyGenericType { - override string toString() { result = "UnboundGenericType" } + override string getPrimaryQlClass() { result = "UnboundGenericType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/UnknownType.qll b/swift/ql/lib/codeql/swift/generated/type/UnknownType.qll index b5c925c0f9e..9b3fe7eb0c0 100644 --- a/swift/ql/lib/codeql/swift/generated/type/UnknownType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/UnknownType.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.type.Type class UnknownTypeBase extends @unknown_type, Type { - override string toString() { result = "UnknownType" } + override string getPrimaryQlClass() { result = "UnknownType" } string getName() { unknown_types(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/type/UnmanagedStorageType.qll b/swift/ql/lib/codeql/swift/generated/type/UnmanagedStorageType.qll index 4ea8526ebb1..3171a6aec32 100644 --- a/swift/ql/lib/codeql/swift/generated/type/UnmanagedStorageType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/UnmanagedStorageType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ReferenceStorageType class UnmanagedStorageTypeBase extends @unmanaged_storage_type, ReferenceStorageType { - override string toString() { result = "UnmanagedStorageType" } + override string getPrimaryQlClass() { result = "UnmanagedStorageType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/UnownedStorageType.qll b/swift/ql/lib/codeql/swift/generated/type/UnownedStorageType.qll index 8cb1f8cd688..6e3c2f1bd23 100644 --- a/swift/ql/lib/codeql/swift/generated/type/UnownedStorageType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/UnownedStorageType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ReferenceStorageType class UnownedStorageTypeBase extends @unowned_storage_type, ReferenceStorageType { - override string toString() { result = "UnownedStorageType" } + override string getPrimaryQlClass() { result = "UnownedStorageType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/UnresolvedType.qll b/swift/ql/lib/codeql/swift/generated/type/UnresolvedType.qll index abab4e4a661..a88083914ef 100644 --- a/swift/ql/lib/codeql/swift/generated/type/UnresolvedType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/UnresolvedType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class UnresolvedTypeBase extends @unresolved_type, Type { - override string toString() { result = "UnresolvedType" } + override string getPrimaryQlClass() { result = "UnresolvedType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/VariadicSequenceType.qll b/swift/ql/lib/codeql/swift/generated/type/VariadicSequenceType.qll index 900b5a8821d..38c85d12a5e 100644 --- a/swift/ql/lib/codeql/swift/generated/type/VariadicSequenceType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/VariadicSequenceType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.UnarySyntaxSugarType class VariadicSequenceTypeBase extends @variadic_sequence_type, UnarySyntaxSugarType { - override string toString() { result = "VariadicSequenceType" } + override string getPrimaryQlClass() { result = "VariadicSequenceType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/WeakStorageType.qll b/swift/ql/lib/codeql/swift/generated/type/WeakStorageType.qll index 31a456058ca..3adb449b4bc 100644 --- a/swift/ql/lib/codeql/swift/generated/type/WeakStorageType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/WeakStorageType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ReferenceStorageType class WeakStorageTypeBase extends @weak_storage_type, ReferenceStorageType { - override string toString() { result = "WeakStorageType" } + override string getPrimaryQlClass() { result = "WeakStorageType" } } From bf71e4c50092c78365915808bf1b914c9c266a81 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Tue, 10 May 2022 12:42:18 +0200 Subject: [PATCH 162/171] Swift: getPrimaryQlClass -> getAPrimaryQlClass --- swift/codegen/templates/ql_class.mustache | 6 ++++-- swift/ql/lib/codeql/swift/generated/Element.qll | 4 +++- swift/ql/lib/codeql/swift/generated/File.qll | 2 +- swift/ql/lib/codeql/swift/generated/Location.qll | 2 +- swift/ql/lib/codeql/swift/generated/UnknownAstNode.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/AccessorDecl.qll | 2 +- .../lib/codeql/swift/generated/decl/AssociatedTypeDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/ClassDecl.qll | 2 +- .../ql/lib/codeql/swift/generated/decl/ConcreteFuncDecl.qll | 2 +- .../ql/lib/codeql/swift/generated/decl/ConcreteVarDecl.qll | 2 +- .../ql/lib/codeql/swift/generated/decl/ConstructorDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/DestructorDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/EnumCaseDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/EnumDecl.qll | 2 +- .../ql/lib/codeql/swift/generated/decl/EnumElementDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/ExtensionDecl.qll | 2 +- .../codeql/swift/generated/decl/GenericTypeParamDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/IfConfigDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/ImportDecl.qll | 2 +- .../lib/codeql/swift/generated/decl/InfixOperatorDecl.qll | 2 +- .../lib/codeql/swift/generated/decl/MissingMemberDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/ModuleDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/OpaqueTypeDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/ParamDecl.qll | 2 +- .../lib/codeql/swift/generated/decl/PatternBindingDecl.qll | 2 +- .../lib/codeql/swift/generated/decl/PostfixOperatorDecl.qll | 2 +- .../lib/codeql/swift/generated/decl/PoundDiagnosticDecl.qll | 2 +- .../lib/codeql/swift/generated/decl/PrecedenceGroupDecl.qll | 2 +- .../lib/codeql/swift/generated/decl/PrefixOperatorDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/ProtocolDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/StructDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/SubscriptDecl.qll | 2 +- .../ql/lib/codeql/swift/generated/decl/TopLevelCodeDecl.qll | 2 +- swift/ql/lib/codeql/swift/generated/decl/TypeAliasDecl.qll | 2 +- .../codeql/swift/generated/expr/AnyHashableErasureExpr.qll | 2 +- .../swift/generated/expr/AppliedPropertyWrapperExpr.qll | 2 +- .../codeql/swift/generated/expr/ArchetypeToSuperExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/Argument.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/ArrayExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/ArrayToPointerExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/ArrowExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/AssignExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/AutoClosureExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/AwaitExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/BinaryExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/BindOptionalExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/BooleanLiteralExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/BridgeFromObjCExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/BridgeToObjCExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/CallExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/CaptureListExpr.qll | 2 +- .../swift/generated/expr/ClassMetatypeToObjectExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/ClosureExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/CodeCompletionExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/CoerceExpr.qll | 2 +- .../swift/generated/expr/CollectionUpcastConversionExpr.qll | 2 +- .../swift/generated/expr/ConditionalBridgeFromObjCExpr.qll | 2 +- .../swift/generated/expr/ConditionalCheckedCastExpr.qll | 2 +- .../codeql/swift/generated/expr/ConstructorRefCallExpr.qll | 2 +- .../generated/expr/CovariantFunctionConversionExpr.qll | 2 +- .../swift/generated/expr/CovariantReturnConversionExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/DeclRefExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/DefaultArgumentExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/DerivedToBaseExpr.qll | 2 +- .../codeql/swift/generated/expr/DestructureTupleExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/DictionaryExpr.qll | 2 +- .../swift/generated/expr/DifferentiableFunctionExpr.qll | 2 +- .../expr/DifferentiableFunctionExtractOriginalExpr.qll | 2 +- .../codeql/swift/generated/expr/DiscardAssignmentExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/DotSelfExpr.qll | 2 +- .../swift/generated/expr/DotSyntaxBaseIgnoredExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/DotSyntaxCallExpr.qll | 2 +- .../codeql/swift/generated/expr/DynamicMemberRefExpr.qll | 2 +- .../codeql/swift/generated/expr/DynamicSubscriptExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/DynamicTypeExpr.qll | 2 +- .../codeql/swift/generated/expr/EditorPlaceholderExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/EnumIsCaseExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/ErasureExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/ErrorExpr.qll | 2 +- .../generated/expr/ExistentialMetatypeToObjectExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/FloatLiteralExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/ForceTryExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/ForceValueExpr.qll | 2 +- .../codeql/swift/generated/expr/ForcedCheckedCastExpr.qll | 2 +- .../swift/generated/expr/ForeignObjectConversionExpr.qll | 2 +- .../codeql/swift/generated/expr/FunctionConversionExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/IfExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/InOutExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/InOutToPointerExpr.qll | 2 +- .../codeql/swift/generated/expr/InjectIntoOptionalExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/IntegerLiteralExpr.qll | 2 +- .../swift/generated/expr/InterpolatedStringLiteralExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/IsExpr.qll | 2 +- .../codeql/swift/generated/expr/KeyPathApplicationExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/KeyPathDotExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/KeyPathExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/LazyInitializerExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/LinearFunctionExpr.qll | 2 +- .../generated/expr/LinearFunctionExtractOriginalExpr.qll | 2 +- .../generated/expr/LinearToDifferentiableFunctionExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/LoadExpr.qll | 2 +- .../swift/generated/expr/MagicIdentifierLiteralExpr.qll | 2 +- .../swift/generated/expr/MakeTemporarilyEscapableExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/MemberRefExpr.qll | 2 +- .../codeql/swift/generated/expr/MetatypeConversionExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/NilLiteralExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/ObjCSelectorExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/ObjectLiteralExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/OneWayExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/OpaqueValueExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/OpenExistentialExpr.qll | 2 +- .../codeql/swift/generated/expr/OptionalEvaluationExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/OptionalTryExpr.qll | 2 +- .../swift/generated/expr/OtherConstructorDeclRefExpr.qll | 2 +- .../codeql/swift/generated/expr/OverloadedDeclRefExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/ParenExpr.qll | 2 +- .../codeql/swift/generated/expr/PointerToPointerExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/PostfixUnaryExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/PrefixUnaryExpr.qll | 2 +- .../generated/expr/PropertyWrapperValuePlaceholderExpr.qll | 2 +- .../swift/generated/expr/ProtocolMetatypeToObjectExpr.qll | 2 +- .../swift/generated/expr/RebindSelfInConstructorExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/RegexLiteralExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/SequenceExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/StringLiteralExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/StringToPointerExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/SubscriptExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/SuperRefExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/TapExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/TryExpr.qll | 2 +- .../ql/lib/codeql/swift/generated/expr/TupleElementExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/TupleExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/expr/TypeExpr.qll | 2 +- .../codeql/swift/generated/expr/UnderlyingToOpaqueExpr.qll | 2 +- .../codeql/swift/generated/expr/UnevaluatedInstanceExpr.qll | 2 +- .../codeql/swift/generated/expr/UnresolvedDeclRefExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/UnresolvedDotExpr.qll | 2 +- .../generated/expr/UnresolvedMemberChainResultExpr.qll | 2 +- .../codeql/swift/generated/expr/UnresolvedMemberExpr.qll | 2 +- .../codeql/swift/generated/expr/UnresolvedPatternExpr.qll | 2 +- .../swift/generated/expr/UnresolvedSpecializeExpr.qll | 2 +- .../swift/generated/expr/UnresolvedTypeConversionExpr.qll | 2 +- .../lib/codeql/swift/generated/expr/VarargExpansionExpr.qll | 2 +- swift/ql/lib/codeql/swift/generated/pattern/AnyPattern.qll | 2 +- .../lib/codeql/swift/generated/pattern/BindingPattern.qll | 2 +- swift/ql/lib/codeql/swift/generated/pattern/BoolPattern.qll | 2 +- .../codeql/swift/generated/pattern/EnumElementPattern.qll | 2 +- swift/ql/lib/codeql/swift/generated/pattern/ExprPattern.qll | 2 +- swift/ql/lib/codeql/swift/generated/pattern/IsPattern.qll | 2 +- .../ql/lib/codeql/swift/generated/pattern/NamedPattern.qll | 2 +- .../codeql/swift/generated/pattern/OptionalSomePattern.qll | 2 +- .../ql/lib/codeql/swift/generated/pattern/ParenPattern.qll | 2 +- .../ql/lib/codeql/swift/generated/pattern/TuplePattern.qll | 2 +- .../ql/lib/codeql/swift/generated/pattern/TypedPattern.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/BraceStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/BreakStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/CaseLabelItem.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/CaseStmt.qll | 2 +- .../ql/lib/codeql/swift/generated/stmt/ConditionElement.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/ContinueStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/DeferStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/DoCatchStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/DoStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/FailStmt.qll | 2 +- .../ql/lib/codeql/swift/generated/stmt/FallthroughStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/ForEachStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/GuardStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/IfStmt.qll | 2 +- .../ql/lib/codeql/swift/generated/stmt/PoundAssertStmt.qll | 2 +- .../ql/lib/codeql/swift/generated/stmt/RepeatWhileStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/ReturnStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/StmtCondition.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/SwitchStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/ThrowStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/WhileStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/stmt/YieldStmt.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/ArraySliceType.qll | 2 +- .../codeql/swift/generated/type/BoundGenericClassType.qll | 2 +- .../codeql/swift/generated/type/BoundGenericEnumType.qll | 2 +- .../codeql/swift/generated/type/BoundGenericStructType.qll | 2 +- .../codeql/swift/generated/type/BuiltinBridgeObjectType.qll | 2 +- .../swift/generated/type/BuiltinDefaultActorStorageType.qll | 2 +- .../lib/codeql/swift/generated/type/BuiltinExecutorType.qll | 2 +- .../ql/lib/codeql/swift/generated/type/BuiltinFloatType.qll | 2 +- .../swift/generated/type/BuiltinIntegerLiteralType.qll | 2 +- .../lib/codeql/swift/generated/type/BuiltinIntegerType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/BuiltinJobType.qll | 2 +- .../codeql/swift/generated/type/BuiltinNativeObjectType.qll | 2 +- .../codeql/swift/generated/type/BuiltinRawPointerType.qll | 2 +- .../generated/type/BuiltinRawUnsafeContinuationType.qll | 2 +- .../swift/generated/type/BuiltinUnsafeValueBufferType.qll | 2 +- .../lib/codeql/swift/generated/type/BuiltinVectorType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/ClassType.qll | 2 +- .../lib/codeql/swift/generated/type/DependentMemberType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/DictionaryType.qll | 2 +- .../ql/lib/codeql/swift/generated/type/DynamicSelfType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/EnumType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/ErrorType.qll | 2 +- .../codeql/swift/generated/type/ExistentialMetatypeType.qll | 2 +- .../ql/lib/codeql/swift/generated/type/ExistentialType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/FunctionType.qll | 2 +- .../lib/codeql/swift/generated/type/GenericFunctionType.qll | 2 +- .../codeql/swift/generated/type/GenericTypeParamType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/InOutType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/LValueType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/MetatypeType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/ModuleType.qll | 2 +- .../lib/codeql/swift/generated/type/NestedArchetypeType.qll | 2 +- .../codeql/swift/generated/type/OpaqueTypeArchetypeType.qll | 2 +- .../lib/codeql/swift/generated/type/OpenedArchetypeType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/OptionalType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/ParenType.qll | 2 +- .../ql/lib/codeql/swift/generated/type/PlaceholderType.qll | 2 +- .../codeql/swift/generated/type/PrimaryArchetypeType.qll | 2 +- .../codeql/swift/generated/type/ProtocolCompositionType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/ProtocolType.qll | 2 +- .../codeql/swift/generated/type/SequenceArchetypeType.qll | 2 +- .../lib/codeql/swift/generated/type/SilBlockStorageType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/SilBoxType.qll | 2 +- .../ql/lib/codeql/swift/generated/type/SilFunctionType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/SilTokenType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/StructType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/TupleType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/TypeAliasType.qll | 2 +- .../ql/lib/codeql/swift/generated/type/TypeVariableType.qll | 2 +- .../lib/codeql/swift/generated/type/UnboundGenericType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/UnknownType.qll | 2 +- .../codeql/swift/generated/type/UnmanagedStorageType.qll | 2 +- .../lib/codeql/swift/generated/type/UnownedStorageType.qll | 2 +- swift/ql/lib/codeql/swift/generated/type/UnresolvedType.qll | 2 +- .../codeql/swift/generated/type/VariadicSequenceType.qll | 2 +- .../ql/lib/codeql/swift/generated/type/WeakStorageType.qll | 2 +- 232 files changed, 237 insertions(+), 233 deletions(-) diff --git a/swift/codegen/templates/ql_class.mustache b/swift/codegen/templates/ql_class.mustache index 3c54467b7c4..8c668de26d4 100644 --- a/swift/codegen/templates/ql_class.mustache +++ b/swift/codegen/templates/ql_class.mustache @@ -8,7 +8,9 @@ class {{name}}Base extends {{db_id}}{{#bases}}, {{.}}{{/bases}} { {{#root}} string toString() { none() } // overridden by subclasses - string getPrimaryQlClass() { none() } // overridden by subclasses + string getAPrimaryQlClass() { none() } // overridden by subclasses + + final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } {{name}}Base getResolveStep() { none() } // overridden by subclasses @@ -19,7 +21,7 @@ class {{name}}Base extends {{db_id}}{{#bases}}, {{.}}{{/bases}} { } {{/root}} {{#final}} - override string getPrimaryQlClass() { result = "{{name}}" } + override string getAPrimaryQlClass() { result = "{{name}}" } {{/final}} {{#properties}} diff --git a/swift/ql/lib/codeql/swift/generated/Element.qll b/swift/ql/lib/codeql/swift/generated/Element.qll index e9f54415ac1..a2c0de1016f 100644 --- a/swift/ql/lib/codeql/swift/generated/Element.qll +++ b/swift/ql/lib/codeql/swift/generated/Element.qll @@ -2,7 +2,9 @@ class ElementBase extends @element { string toString() { none() } // overridden by subclasses - string getPrimaryQlClass() { none() } // overridden by subclasses + string getAPrimaryQlClass() { none() } // overridden by subclasses + + final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } ElementBase getResolveStep() { none() } // overridden by subclasses diff --git a/swift/ql/lib/codeql/swift/generated/File.qll b/swift/ql/lib/codeql/swift/generated/File.qll index a0cde68c73a..38f1ea107a7 100644 --- a/swift/ql/lib/codeql/swift/generated/File.qll +++ b/swift/ql/lib/codeql/swift/generated/File.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.Element class FileBase extends @file, Element { - override string getPrimaryQlClass() { result = "File" } + override string getAPrimaryQlClass() { result = "File" } string getName() { files(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/Location.qll b/swift/ql/lib/codeql/swift/generated/Location.qll index a39ee13823c..8379e4a5259 100644 --- a/swift/ql/lib/codeql/swift/generated/Location.qll +++ b/swift/ql/lib/codeql/swift/generated/Location.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.Element import codeql.swift.elements.File class LocationBase extends @location, Element { - override string getPrimaryQlClass() { result = "Location" } + override string getAPrimaryQlClass() { result = "Location" } File getFile() { exists(File x | diff --git a/swift/ql/lib/codeql/swift/generated/UnknownAstNode.qll b/swift/ql/lib/codeql/swift/generated/UnknownAstNode.qll index 06bca7af67d..b3fe1fd4587 100644 --- a/swift/ql/lib/codeql/swift/generated/UnknownAstNode.qll +++ b/swift/ql/lib/codeql/swift/generated/UnknownAstNode.qll @@ -6,7 +6,7 @@ import codeql.swift.elements.stmt.Stmt import codeql.swift.elements.typerepr.TypeRepr class UnknownAstNodeBase extends @unknown_ast_node, Decl, Expr, Pattern, Stmt, TypeRepr { - override string getPrimaryQlClass() { result = "UnknownAstNode" } + override string getAPrimaryQlClass() { result = "UnknownAstNode" } string getName() { unknown_ast_nodes(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/AccessorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/AccessorDecl.qll index 5ac3dd7091a..d293463d999 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/AccessorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/AccessorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.FuncDecl class AccessorDeclBase extends @accessor_decl, FuncDecl { - override string getPrimaryQlClass() { result = "AccessorDecl" } + override string getAPrimaryQlClass() { result = "AccessorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/AssociatedTypeDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/AssociatedTypeDecl.qll index e7970236870..efd33b04d8c 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/AssociatedTypeDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/AssociatedTypeDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.AbstractTypeParamDecl class AssociatedTypeDeclBase extends @associated_type_decl, AbstractTypeParamDecl { - override string getPrimaryQlClass() { result = "AssociatedTypeDecl" } + override string getAPrimaryQlClass() { result = "AssociatedTypeDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ClassDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ClassDecl.qll index 07d6d63128f..d770f1f7b4f 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ClassDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ClassDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.NominalTypeDecl class ClassDeclBase extends @class_decl, NominalTypeDecl { - override string getPrimaryQlClass() { result = "ClassDecl" } + override string getAPrimaryQlClass() { result = "ClassDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ConcreteFuncDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ConcreteFuncDecl.qll index e34421da66d..0ba9db75056 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ConcreteFuncDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ConcreteFuncDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.FuncDecl class ConcreteFuncDeclBase extends @concrete_func_decl, FuncDecl { - override string getPrimaryQlClass() { result = "ConcreteFuncDecl" } + override string getAPrimaryQlClass() { result = "ConcreteFuncDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ConcreteVarDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ConcreteVarDecl.qll index c6564834c5f..5be11bfe33a 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ConcreteVarDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ConcreteVarDecl.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.decl.VarDecl class ConcreteVarDeclBase extends @concrete_var_decl, VarDecl { - override string getPrimaryQlClass() { result = "ConcreteVarDecl" } + override string getAPrimaryQlClass() { result = "ConcreteVarDecl" } int getIntroducerInt() { concrete_var_decls(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ConstructorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ConstructorDecl.qll index fbd9db1e299..208804ca71a 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ConstructorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ConstructorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.AbstractFunctionDecl class ConstructorDeclBase extends @constructor_decl, AbstractFunctionDecl { - override string getPrimaryQlClass() { result = "ConstructorDecl" } + override string getAPrimaryQlClass() { result = "ConstructorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/DestructorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/DestructorDecl.qll index 667650662a0..647dbe8daec 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/DestructorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/DestructorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.AbstractFunctionDecl class DestructorDeclBase extends @destructor_decl, AbstractFunctionDecl { - override string getPrimaryQlClass() { result = "DestructorDecl" } + override string getAPrimaryQlClass() { result = "DestructorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/EnumCaseDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/EnumCaseDecl.qll index 654da108fa0..179552ebf94 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/EnumCaseDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/EnumCaseDecl.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.decl.Decl import codeql.swift.elements.decl.EnumElementDecl class EnumCaseDeclBase extends @enum_case_decl, Decl { - override string getPrimaryQlClass() { result = "EnumCaseDecl" } + override string getAPrimaryQlClass() { result = "EnumCaseDecl" } EnumElementDecl getElement(int index) { exists(EnumElementDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/decl/EnumDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/EnumDecl.qll index 75120af5548..ae84dea0998 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/EnumDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/EnumDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.NominalTypeDecl class EnumDeclBase extends @enum_decl, NominalTypeDecl { - override string getPrimaryQlClass() { result = "EnumDecl" } + override string getAPrimaryQlClass() { result = "EnumDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/EnumElementDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/EnumElementDecl.qll index 0210e22ddda..5a7cc81bb31 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/EnumElementDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/EnumElementDecl.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.decl.ParamDecl import codeql.swift.elements.decl.ValueDecl class EnumElementDeclBase extends @enum_element_decl, ValueDecl { - override string getPrimaryQlClass() { result = "EnumElementDecl" } + override string getAPrimaryQlClass() { result = "EnumElementDecl" } string getName() { enum_element_decls(this, result) } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ExtensionDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ExtensionDecl.qll index fff23dbeb47..0efc904e43a 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ExtensionDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ExtensionDecl.qll @@ -4,5 +4,5 @@ import codeql.swift.elements.decl.GenericContext import codeql.swift.elements.decl.IterableDeclContext class ExtensionDeclBase extends @extension_decl, Decl, GenericContext, IterableDeclContext { - override string getPrimaryQlClass() { result = "ExtensionDecl" } + override string getAPrimaryQlClass() { result = "ExtensionDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/GenericTypeParamDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/GenericTypeParamDecl.qll index 9cc79737f0b..990d69d1734 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/GenericTypeParamDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/GenericTypeParamDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.AbstractTypeParamDecl class GenericTypeParamDeclBase extends @generic_type_param_decl, AbstractTypeParamDecl { - override string getPrimaryQlClass() { result = "GenericTypeParamDecl" } + override string getAPrimaryQlClass() { result = "GenericTypeParamDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/IfConfigDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/IfConfigDecl.qll index bcc629577d9..578051e9f8b 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/IfConfigDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/IfConfigDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.Decl class IfConfigDeclBase extends @if_config_decl, Decl { - override string getPrimaryQlClass() { result = "IfConfigDecl" } + override string getAPrimaryQlClass() { result = "IfConfigDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ImportDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ImportDecl.qll index e2b9a59a72d..fdd89db170a 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ImportDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ImportDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.Decl class ImportDeclBase extends @import_decl, Decl { - override string getPrimaryQlClass() { result = "ImportDecl" } + override string getAPrimaryQlClass() { result = "ImportDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/InfixOperatorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/InfixOperatorDecl.qll index bac4345e86d..66910347c9d 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/InfixOperatorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/InfixOperatorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.OperatorDecl class InfixOperatorDeclBase extends @infix_operator_decl, OperatorDecl { - override string getPrimaryQlClass() { result = "InfixOperatorDecl" } + override string getAPrimaryQlClass() { result = "InfixOperatorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/MissingMemberDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/MissingMemberDecl.qll index 046fece53b5..bc6002e56d2 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/MissingMemberDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/MissingMemberDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.Decl class MissingMemberDeclBase extends @missing_member_decl, Decl { - override string getPrimaryQlClass() { result = "MissingMemberDecl" } + override string getAPrimaryQlClass() { result = "MissingMemberDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ModuleDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ModuleDecl.qll index 94fac5a140b..aad5d00c0c6 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ModuleDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ModuleDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.TypeDecl class ModuleDeclBase extends @module_decl, TypeDecl { - override string getPrimaryQlClass() { result = "ModuleDecl" } + override string getAPrimaryQlClass() { result = "ModuleDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/OpaqueTypeDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/OpaqueTypeDecl.qll index 87307cf27b1..42b8679dde0 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/OpaqueTypeDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/OpaqueTypeDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.GenericTypeDecl class OpaqueTypeDeclBase extends @opaque_type_decl, GenericTypeDecl { - override string getPrimaryQlClass() { result = "OpaqueTypeDecl" } + override string getAPrimaryQlClass() { result = "OpaqueTypeDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ParamDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ParamDecl.qll index 455f504e777..079c1cba19e 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ParamDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ParamDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.VarDecl class ParamDeclBase extends @param_decl, VarDecl { - override string getPrimaryQlClass() { result = "ParamDecl" } + override string getAPrimaryQlClass() { result = "ParamDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll index 6b69930402e..44c80c76efa 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/PatternBindingDecl.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.pattern.Pattern class PatternBindingDeclBase extends @pattern_binding_decl, Decl { - override string getPrimaryQlClass() { result = "PatternBindingDecl" } + override string getAPrimaryQlClass() { result = "PatternBindingDecl" } Expr getInit(int index) { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/decl/PostfixOperatorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/PostfixOperatorDecl.qll index 4786bb2eb08..a52d858f853 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/PostfixOperatorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/PostfixOperatorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.OperatorDecl class PostfixOperatorDeclBase extends @postfix_operator_decl, OperatorDecl { - override string getPrimaryQlClass() { result = "PostfixOperatorDecl" } + override string getAPrimaryQlClass() { result = "PostfixOperatorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/PoundDiagnosticDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/PoundDiagnosticDecl.qll index ba7d98fde10..32f723ae081 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/PoundDiagnosticDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/PoundDiagnosticDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.Decl class PoundDiagnosticDeclBase extends @pound_diagnostic_decl, Decl { - override string getPrimaryQlClass() { result = "PoundDiagnosticDecl" } + override string getAPrimaryQlClass() { result = "PoundDiagnosticDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/PrecedenceGroupDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/PrecedenceGroupDecl.qll index a963aeff10d..381b92ed030 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/PrecedenceGroupDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/PrecedenceGroupDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.Decl class PrecedenceGroupDeclBase extends @precedence_group_decl, Decl { - override string getPrimaryQlClass() { result = "PrecedenceGroupDecl" } + override string getAPrimaryQlClass() { result = "PrecedenceGroupDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/PrefixOperatorDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/PrefixOperatorDecl.qll index 01db13ad940..5f66eb16fc9 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/PrefixOperatorDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/PrefixOperatorDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.OperatorDecl class PrefixOperatorDeclBase extends @prefix_operator_decl, OperatorDecl { - override string getPrimaryQlClass() { result = "PrefixOperatorDecl" } + override string getAPrimaryQlClass() { result = "PrefixOperatorDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/ProtocolDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/ProtocolDecl.qll index 29fcf2b507a..1c57a13aae7 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/ProtocolDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/ProtocolDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.NominalTypeDecl class ProtocolDeclBase extends @protocol_decl, NominalTypeDecl { - override string getPrimaryQlClass() { result = "ProtocolDecl" } + override string getAPrimaryQlClass() { result = "ProtocolDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/StructDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/StructDecl.qll index 26455f15484..135efec442a 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/StructDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/StructDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.NominalTypeDecl class StructDeclBase extends @struct_decl, NominalTypeDecl { - override string getPrimaryQlClass() { result = "StructDecl" } + override string getAPrimaryQlClass() { result = "StructDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/SubscriptDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/SubscriptDecl.qll index 6329f269f49..5d916618229 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/SubscriptDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/SubscriptDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.AbstractStorageDecl class SubscriptDeclBase extends @subscript_decl, AbstractStorageDecl { - override string getPrimaryQlClass() { result = "SubscriptDecl" } + override string getAPrimaryQlClass() { result = "SubscriptDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/decl/TopLevelCodeDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/TopLevelCodeDecl.qll index 87899c24bfe..7c664ad9bca 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/TopLevelCodeDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/TopLevelCodeDecl.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.BraceStmt import codeql.swift.elements.decl.Decl class TopLevelCodeDeclBase extends @top_level_code_decl, Decl { - override string getPrimaryQlClass() { result = "TopLevelCodeDecl" } + override string getAPrimaryQlClass() { result = "TopLevelCodeDecl" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/decl/TypeAliasDecl.qll b/swift/ql/lib/codeql/swift/generated/decl/TypeAliasDecl.qll index d5a41a716bc..fd437a62676 100644 --- a/swift/ql/lib/codeql/swift/generated/decl/TypeAliasDecl.qll +++ b/swift/ql/lib/codeql/swift/generated/decl/TypeAliasDecl.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.decl.GenericTypeDecl class TypeAliasDeclBase extends @type_alias_decl, GenericTypeDecl { - override string getPrimaryQlClass() { result = "TypeAliasDecl" } + override string getAPrimaryQlClass() { result = "TypeAliasDecl" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/AnyHashableErasureExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/AnyHashableErasureExpr.qll index de5c1534faf..6e95203d957 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/AnyHashableErasureExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/AnyHashableErasureExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class AnyHashableErasureExprBase extends @any_hashable_erasure_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "AnyHashableErasureExpr" } + override string getAPrimaryQlClass() { result = "AnyHashableErasureExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/AppliedPropertyWrapperExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/AppliedPropertyWrapperExpr.qll index e0f95ba2a02..9fb974487e7 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/AppliedPropertyWrapperExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/AppliedPropertyWrapperExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class AppliedPropertyWrapperExprBase extends @applied_property_wrapper_expr, Expr { - override string getPrimaryQlClass() { result = "AppliedPropertyWrapperExpr" } + override string getAPrimaryQlClass() { result = "AppliedPropertyWrapperExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ArchetypeToSuperExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ArchetypeToSuperExpr.qll index e5123e26e53..7e9a9e4a7b8 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ArchetypeToSuperExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ArchetypeToSuperExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ArchetypeToSuperExprBase extends @archetype_to_super_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "ArchetypeToSuperExpr" } + override string getAPrimaryQlClass() { result = "ArchetypeToSuperExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/Argument.qll b/swift/ql/lib/codeql/swift/generated/expr/Argument.qll index 0a3cdae3a66..9f16b90e3fe 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/Argument.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/Argument.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.Element import codeql.swift.elements.expr.Expr class ArgumentBase extends @argument, Element { - override string getPrimaryQlClass() { result = "Argument" } + override string getAPrimaryQlClass() { result = "Argument" } string getLabel() { arguments(this, result, _) } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ArrayExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ArrayExpr.qll index 6a9cddd47ce..e62af8dde55 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ArrayExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ArrayExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.CollectionExpr import codeql.swift.elements.expr.Expr class ArrayExprBase extends @array_expr, CollectionExpr { - override string getPrimaryQlClass() { result = "ArrayExpr" } + override string getAPrimaryQlClass() { result = "ArrayExpr" } Expr getElement(int index) { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/ArrayToPointerExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ArrayToPointerExpr.qll index 3d1b8c96d79..0eef1004773 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ArrayToPointerExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ArrayToPointerExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ArrayToPointerExprBase extends @array_to_pointer_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "ArrayToPointerExpr" } + override string getAPrimaryQlClass() { result = "ArrayToPointerExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ArrowExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ArrowExpr.qll index a8dc1d1c8fe..a10d68af913 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ArrowExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ArrowExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class ArrowExprBase extends @arrow_expr, Expr { - override string getPrimaryQlClass() { result = "ArrowExpr" } + override string getAPrimaryQlClass() { result = "ArrowExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/AssignExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/AssignExpr.qll index 743a4de6cf0..b733f8fc3e2 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/AssignExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/AssignExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class AssignExprBase extends @assign_expr, Expr { - override string getPrimaryQlClass() { result = "AssignExpr" } + override string getAPrimaryQlClass() { result = "AssignExpr" } Expr getDest() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/AutoClosureExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/AutoClosureExpr.qll index 05cccdedea8..f25248ed0fb 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/AutoClosureExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/AutoClosureExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.AbstractClosureExpr import codeql.swift.elements.stmt.BraceStmt class AutoClosureExprBase extends @auto_closure_expr, AbstractClosureExpr { - override string getPrimaryQlClass() { result = "AutoClosureExpr" } + override string getAPrimaryQlClass() { result = "AutoClosureExpr" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/AwaitExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/AwaitExpr.qll index abb9a883381..e18243db73a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/AwaitExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/AwaitExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.IdentityExpr class AwaitExprBase extends @await_expr, IdentityExpr { - override string getPrimaryQlClass() { result = "AwaitExpr" } + override string getAPrimaryQlClass() { result = "AwaitExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/BinaryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/BinaryExpr.qll index e7a10adbc86..54895bbf294 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/BinaryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/BinaryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ApplyExpr class BinaryExprBase extends @binary_expr, ApplyExpr { - override string getPrimaryQlClass() { result = "BinaryExpr" } + override string getAPrimaryQlClass() { result = "BinaryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/BindOptionalExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/BindOptionalExpr.qll index e66a617f7c5..9cd270891ea 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/BindOptionalExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/BindOptionalExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class BindOptionalExprBase extends @bind_optional_expr, Expr { - override string getPrimaryQlClass() { result = "BindOptionalExpr" } + override string getAPrimaryQlClass() { result = "BindOptionalExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/BooleanLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/BooleanLiteralExpr.qll index 98616ad15f3..853c8f08629 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/BooleanLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/BooleanLiteralExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.BuiltinLiteralExpr class BooleanLiteralExprBase extends @boolean_literal_expr, BuiltinLiteralExpr { - override string getPrimaryQlClass() { result = "BooleanLiteralExpr" } + override string getAPrimaryQlClass() { result = "BooleanLiteralExpr" } boolean getValue() { boolean_literal_exprs(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/BridgeFromObjCExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/BridgeFromObjCExpr.qll index 6f5a6e38f4e..fc30c1b3f81 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/BridgeFromObjCExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/BridgeFromObjCExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class BridgeFromObjCExprBase extends @bridge_from_obj_c_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "BridgeFromObjCExpr" } + override string getAPrimaryQlClass() { result = "BridgeFromObjCExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/BridgeToObjCExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/BridgeToObjCExpr.qll index 39f31e77f55..da3cf85dc97 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/BridgeToObjCExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/BridgeToObjCExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class BridgeToObjCExprBase extends @bridge_to_obj_c_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "BridgeToObjCExpr" } + override string getAPrimaryQlClass() { result = "BridgeToObjCExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CallExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CallExpr.qll index 6a3329711e6..55dd803ce7d 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CallExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CallExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ApplyExpr class CallExprBase extends @call_expr, ApplyExpr { - override string getPrimaryQlClass() { result = "CallExpr" } + override string getAPrimaryQlClass() { result = "CallExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CaptureListExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CaptureListExpr.qll index 76aac82934e..5e273ab1e4c 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CaptureListExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CaptureListExpr.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.decl.PatternBindingDecl class CaptureListExprBase extends @capture_list_expr, Expr { - override string getPrimaryQlClass() { result = "CaptureListExpr" } + override string getAPrimaryQlClass() { result = "CaptureListExpr" } PatternBindingDecl getBindingDecl(int index) { exists(PatternBindingDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/ClassMetatypeToObjectExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ClassMetatypeToObjectExpr.qll index ec91100ecde..aaae45957cf 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ClassMetatypeToObjectExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ClassMetatypeToObjectExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ClassMetatypeToObjectExprBase extends @class_metatype_to_object_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "ClassMetatypeToObjectExpr" } + override string getAPrimaryQlClass() { result = "ClassMetatypeToObjectExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ClosureExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ClosureExpr.qll index 5e8022d348c..e1c1261654c 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ClosureExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ClosureExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.AbstractClosureExpr import codeql.swift.elements.stmt.BraceStmt class ClosureExprBase extends @closure_expr, AbstractClosureExpr { - override string getPrimaryQlClass() { result = "ClosureExpr" } + override string getAPrimaryQlClass() { result = "ClosureExpr" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/CodeCompletionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CodeCompletionExpr.qll index 34b3bb695b6..853f721ebb9 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CodeCompletionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CodeCompletionExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class CodeCompletionExprBase extends @code_completion_expr, Expr { - override string getPrimaryQlClass() { result = "CodeCompletionExpr" } + override string getAPrimaryQlClass() { result = "CodeCompletionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CoerceExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CoerceExpr.qll index 90db24a184b..b11218595cb 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CoerceExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CoerceExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ExplicitCastExpr class CoerceExprBase extends @coerce_expr, ExplicitCastExpr { - override string getPrimaryQlClass() { result = "CoerceExpr" } + override string getAPrimaryQlClass() { result = "CoerceExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CollectionUpcastConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CollectionUpcastConversionExpr.qll index 7e3bd15a64c..92dab3f54e0 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CollectionUpcastConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CollectionUpcastConversionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class CollectionUpcastConversionExprBase extends @collection_upcast_conversion_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "CollectionUpcastConversionExpr" } + override string getAPrimaryQlClass() { result = "CollectionUpcastConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ConditionalBridgeFromObjCExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ConditionalBridgeFromObjCExpr.qll index 05a627f8274..20a192b6c03 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ConditionalBridgeFromObjCExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ConditionalBridgeFromObjCExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ConditionalBridgeFromObjCExprBase extends @conditional_bridge_from_obj_c_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "ConditionalBridgeFromObjCExpr" } + override string getAPrimaryQlClass() { result = "ConditionalBridgeFromObjCExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ConditionalCheckedCastExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ConditionalCheckedCastExpr.qll index bfc5a53cb8d..d38199d4275 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ConditionalCheckedCastExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ConditionalCheckedCastExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.CheckedCastExpr class ConditionalCheckedCastExprBase extends @conditional_checked_cast_expr, CheckedCastExpr { - override string getPrimaryQlClass() { result = "ConditionalCheckedCastExpr" } + override string getAPrimaryQlClass() { result = "ConditionalCheckedCastExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ConstructorRefCallExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ConstructorRefCallExpr.qll index 33d454916ca..6d379b8576b 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ConstructorRefCallExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ConstructorRefCallExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.SelfApplyExpr class ConstructorRefCallExprBase extends @constructor_ref_call_expr, SelfApplyExpr { - override string getPrimaryQlClass() { result = "ConstructorRefCallExpr" } + override string getAPrimaryQlClass() { result = "ConstructorRefCallExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CovariantFunctionConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CovariantFunctionConversionExpr.qll index 1fec877c953..56837b28e22 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CovariantFunctionConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CovariantFunctionConversionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class CovariantFunctionConversionExprBase extends @covariant_function_conversion_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "CovariantFunctionConversionExpr" } + override string getAPrimaryQlClass() { result = "CovariantFunctionConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/CovariantReturnConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/CovariantReturnConversionExpr.qll index 4e7199cdc33..1df6850ead7 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/CovariantReturnConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/CovariantReturnConversionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class CovariantReturnConversionExprBase extends @covariant_return_conversion_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "CovariantReturnConversionExpr" } + override string getAPrimaryQlClass() { result = "CovariantReturnConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DeclRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DeclRefExpr.qll index 7093a892a74..11d81e5aecf 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DeclRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DeclRefExpr.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.type.Type class DeclRefExprBase extends @decl_ref_expr, Expr { - override string getPrimaryQlClass() { result = "DeclRefExpr" } + override string getAPrimaryQlClass() { result = "DeclRefExpr" } Decl getDecl() { exists(Decl x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/DefaultArgumentExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DefaultArgumentExpr.qll index 6374fa961f9..e959c9c4a44 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DefaultArgumentExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DefaultArgumentExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.decl.ParamDecl class DefaultArgumentExprBase extends @default_argument_expr, Expr { - override string getPrimaryQlClass() { result = "DefaultArgumentExpr" } + override string getAPrimaryQlClass() { result = "DefaultArgumentExpr" } ParamDecl getParamDecl() { exists(ParamDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/DerivedToBaseExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DerivedToBaseExpr.qll index 554eb512d5a..96ab92b74a9 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DerivedToBaseExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DerivedToBaseExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class DerivedToBaseExprBase extends @derived_to_base_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "DerivedToBaseExpr" } + override string getAPrimaryQlClass() { result = "DerivedToBaseExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DestructureTupleExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DestructureTupleExpr.qll index b7b376b7f38..e21812e0c3d 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DestructureTupleExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DestructureTupleExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class DestructureTupleExprBase extends @destructure_tuple_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "DestructureTupleExpr" } + override string getAPrimaryQlClass() { result = "DestructureTupleExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DictionaryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DictionaryExpr.qll index 49fe6818051..1daef547291 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DictionaryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DictionaryExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.CollectionExpr import codeql.swift.elements.expr.Expr class DictionaryExprBase extends @dictionary_expr, CollectionExpr { - override string getPrimaryQlClass() { result = "DictionaryExpr" } + override string getAPrimaryQlClass() { result = "DictionaryExpr" } Expr getElement(int index) { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExpr.qll index e864e68e73a..1b27a3888be 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class DifferentiableFunctionExprBase extends @differentiable_function_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "DifferentiableFunctionExpr" } + override string getAPrimaryQlClass() { result = "DifferentiableFunctionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExtractOriginalExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExtractOriginalExpr.qll index 790877fa186..039056df150 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExtractOriginalExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DifferentiableFunctionExtractOriginalExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class DifferentiableFunctionExtractOriginalExprBase extends @differentiable_function_extract_original_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "DifferentiableFunctionExtractOriginalExpr" } + override string getAPrimaryQlClass() { result = "DifferentiableFunctionExtractOriginalExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DiscardAssignmentExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DiscardAssignmentExpr.qll index e9470dab89a..3e1971fbc61 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DiscardAssignmentExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DiscardAssignmentExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class DiscardAssignmentExprBase extends @discard_assignment_expr, Expr { - override string getPrimaryQlClass() { result = "DiscardAssignmentExpr" } + override string getAPrimaryQlClass() { result = "DiscardAssignmentExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DotSelfExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DotSelfExpr.qll index 8df593c6c84..4c93babb697 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DotSelfExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DotSelfExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.IdentityExpr class DotSelfExprBase extends @dot_self_expr, IdentityExpr { - override string getPrimaryQlClass() { result = "DotSelfExpr" } + override string getAPrimaryQlClass() { result = "DotSelfExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxBaseIgnoredExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxBaseIgnoredExpr.qll index 6a4f9148640..bf5f76b3229 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxBaseIgnoredExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxBaseIgnoredExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class DotSyntaxBaseIgnoredExprBase extends @dot_syntax_base_ignored_expr, Expr { - override string getPrimaryQlClass() { result = "DotSyntaxBaseIgnoredExpr" } + override string getAPrimaryQlClass() { result = "DotSyntaxBaseIgnoredExpr" } Expr getQualifier() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxCallExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxCallExpr.qll index d5d2f53db6f..c026f329bce 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxCallExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DotSyntaxCallExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.SelfApplyExpr class DotSyntaxCallExprBase extends @dot_syntax_call_expr, SelfApplyExpr { - override string getPrimaryQlClass() { result = "DotSyntaxCallExpr" } + override string getAPrimaryQlClass() { result = "DotSyntaxCallExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DynamicMemberRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DynamicMemberRefExpr.qll index b03992c2f89..fd4291b5ee0 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DynamicMemberRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DynamicMemberRefExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.DynamicLookupExpr class DynamicMemberRefExprBase extends @dynamic_member_ref_expr, DynamicLookupExpr { - override string getPrimaryQlClass() { result = "DynamicMemberRefExpr" } + override string getAPrimaryQlClass() { result = "DynamicMemberRefExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DynamicSubscriptExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DynamicSubscriptExpr.qll index f3ebf5db289..a920f1b4329 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DynamicSubscriptExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DynamicSubscriptExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.DynamicLookupExpr class DynamicSubscriptExprBase extends @dynamic_subscript_expr, DynamicLookupExpr { - override string getPrimaryQlClass() { result = "DynamicSubscriptExpr" } + override string getAPrimaryQlClass() { result = "DynamicSubscriptExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/DynamicTypeExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/DynamicTypeExpr.qll index 651088dcdc7..c43659d6dd1 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/DynamicTypeExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/DynamicTypeExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class DynamicTypeExprBase extends @dynamic_type_expr, Expr { - override string getPrimaryQlClass() { result = "DynamicTypeExpr" } + override string getAPrimaryQlClass() { result = "DynamicTypeExpr" } Expr getBaseExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/EditorPlaceholderExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/EditorPlaceholderExpr.qll index 13b01ebe579..ce5397171b7 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/EditorPlaceholderExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/EditorPlaceholderExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class EditorPlaceholderExprBase extends @editor_placeholder_expr, Expr { - override string getPrimaryQlClass() { result = "EditorPlaceholderExpr" } + override string getAPrimaryQlClass() { result = "EditorPlaceholderExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/EnumIsCaseExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/EnumIsCaseExpr.qll index 7671d1fe187..e02b97813a4 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/EnumIsCaseExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/EnumIsCaseExpr.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.typerepr.TypeRepr class EnumIsCaseExprBase extends @enum_is_case_expr, Expr { - override string getPrimaryQlClass() { result = "EnumIsCaseExpr" } + override string getAPrimaryQlClass() { result = "EnumIsCaseExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/ErasureExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ErasureExpr.qll index 8f4006a35d8..9e3a585d8e7 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ErasureExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ErasureExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ErasureExprBase extends @erasure_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "ErasureExpr" } + override string getAPrimaryQlClass() { result = "ErasureExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ErrorExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ErrorExpr.qll index c93afa1d20d..224560ba9a6 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ErrorExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ErrorExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class ErrorExprBase extends @error_expr, Expr { - override string getPrimaryQlClass() { result = "ErrorExpr" } + override string getAPrimaryQlClass() { result = "ErrorExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ExistentialMetatypeToObjectExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ExistentialMetatypeToObjectExpr.qll index 474ef8d876a..065a08ad391 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ExistentialMetatypeToObjectExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ExistentialMetatypeToObjectExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ExistentialMetatypeToObjectExprBase extends @existential_metatype_to_object_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "ExistentialMetatypeToObjectExpr" } + override string getAPrimaryQlClass() { result = "ExistentialMetatypeToObjectExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/FloatLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/FloatLiteralExpr.qll index d6355497331..984819e59aa 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/FloatLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/FloatLiteralExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.NumberLiteralExpr class FloatLiteralExprBase extends @float_literal_expr, NumberLiteralExpr { - override string getPrimaryQlClass() { result = "FloatLiteralExpr" } + override string getAPrimaryQlClass() { result = "FloatLiteralExpr" } string getStringValue() { float_literal_exprs(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ForceTryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ForceTryExpr.qll index 077dff2565a..79596be65fa 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ForceTryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ForceTryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.AnyTryExpr class ForceTryExprBase extends @force_try_expr, AnyTryExpr { - override string getPrimaryQlClass() { result = "ForceTryExpr" } + override string getAPrimaryQlClass() { result = "ForceTryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ForceValueExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ForceValueExpr.qll index a5af8ecd64f..224dc78316e 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ForceValueExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ForceValueExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class ForceValueExprBase extends @force_value_expr, Expr { - override string getPrimaryQlClass() { result = "ForceValueExpr" } + override string getAPrimaryQlClass() { result = "ForceValueExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/ForcedCheckedCastExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ForcedCheckedCastExpr.qll index cbcd27323ca..0f1a2e44637 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ForcedCheckedCastExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ForcedCheckedCastExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.CheckedCastExpr class ForcedCheckedCastExprBase extends @forced_checked_cast_expr, CheckedCastExpr { - override string getPrimaryQlClass() { result = "ForcedCheckedCastExpr" } + override string getAPrimaryQlClass() { result = "ForcedCheckedCastExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ForeignObjectConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ForeignObjectConversionExpr.qll index 685cb980165..ab40420b67b 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ForeignObjectConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ForeignObjectConversionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ForeignObjectConversionExprBase extends @foreign_object_conversion_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "ForeignObjectConversionExpr" } + override string getAPrimaryQlClass() { result = "ForeignObjectConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/FunctionConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/FunctionConversionExpr.qll index e996cea15c1..c6e771f3f11 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/FunctionConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/FunctionConversionExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class FunctionConversionExprBase extends @function_conversion_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "FunctionConversionExpr" } + override string getAPrimaryQlClass() { result = "FunctionConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/IfExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/IfExpr.qll index 491d4c4b315..b1ec1a192f7 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/IfExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/IfExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class IfExprBase extends @if_expr, Expr { - override string getPrimaryQlClass() { result = "IfExpr" } + override string getAPrimaryQlClass() { result = "IfExpr" } Expr getCondition() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/InOutExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/InOutExpr.qll index d54b02880dc..43da09784ae 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/InOutExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/InOutExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class InOutExprBase extends @in_out_expr, Expr { - override string getPrimaryQlClass() { result = "InOutExpr" } + override string getAPrimaryQlClass() { result = "InOutExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/InOutToPointerExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/InOutToPointerExpr.qll index 19b8a0c8feb..d158c645de4 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/InOutToPointerExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/InOutToPointerExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class InOutToPointerExprBase extends @in_out_to_pointer_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "InOutToPointerExpr" } + override string getAPrimaryQlClass() { result = "InOutToPointerExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/InjectIntoOptionalExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/InjectIntoOptionalExpr.qll index af91274bdad..cedf59de7bf 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/InjectIntoOptionalExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/InjectIntoOptionalExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class InjectIntoOptionalExprBase extends @inject_into_optional_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "InjectIntoOptionalExpr" } + override string getAPrimaryQlClass() { result = "InjectIntoOptionalExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/IntegerLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/IntegerLiteralExpr.qll index 2599e9926ee..dcd8f4b97a5 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/IntegerLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/IntegerLiteralExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.NumberLiteralExpr class IntegerLiteralExprBase extends @integer_literal_expr, NumberLiteralExpr { - override string getPrimaryQlClass() { result = "IntegerLiteralExpr" } + override string getAPrimaryQlClass() { result = "IntegerLiteralExpr" } string getStringValue() { integer_literal_exprs(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/InterpolatedStringLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/InterpolatedStringLiteralExpr.qll index 74e9062c995..72f0fdac418 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/InterpolatedStringLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/InterpolatedStringLiteralExpr.qll @@ -5,7 +5,7 @@ import codeql.swift.elements.expr.OpaqueValueExpr import codeql.swift.elements.expr.TapExpr class InterpolatedStringLiteralExprBase extends @interpolated_string_literal_expr, LiteralExpr { - override string getPrimaryQlClass() { result = "InterpolatedStringLiteralExpr" } + override string getAPrimaryQlClass() { result = "InterpolatedStringLiteralExpr" } OpaqueValueExpr getInterpolationExpr() { exists(OpaqueValueExpr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/IsExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/IsExpr.qll index 2591820191a..45ddca73d8e 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/IsExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/IsExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.CheckedCastExpr class IsExprBase extends @is_expr, CheckedCastExpr { - override string getPrimaryQlClass() { result = "IsExpr" } + override string getAPrimaryQlClass() { result = "IsExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/KeyPathApplicationExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/KeyPathApplicationExpr.qll index 920c4248f26..e746c44943b 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/KeyPathApplicationExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/KeyPathApplicationExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class KeyPathApplicationExprBase extends @key_path_application_expr, Expr { - override string getPrimaryQlClass() { result = "KeyPathApplicationExpr" } + override string getAPrimaryQlClass() { result = "KeyPathApplicationExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/KeyPathDotExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/KeyPathDotExpr.qll index ac04f37e7fe..fbd58631fd4 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/KeyPathDotExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/KeyPathDotExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class KeyPathDotExprBase extends @key_path_dot_expr, Expr { - override string getPrimaryQlClass() { result = "KeyPathDotExpr" } + override string getAPrimaryQlClass() { result = "KeyPathDotExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/KeyPathExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/KeyPathExpr.qll index ccd1596a863..7ac3d4614f0 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/KeyPathExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/KeyPathExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class KeyPathExprBase extends @key_path_expr, Expr { - override string getPrimaryQlClass() { result = "KeyPathExpr" } + override string getAPrimaryQlClass() { result = "KeyPathExpr" } Expr getParsedRoot() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/LazyInitializerExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/LazyInitializerExpr.qll index 8f83e5efb42..b38aa2ebd5a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/LazyInitializerExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/LazyInitializerExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class LazyInitializerExprBase extends @lazy_initializer_expr, Expr { - override string getPrimaryQlClass() { result = "LazyInitializerExpr" } + override string getAPrimaryQlClass() { result = "LazyInitializerExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExpr.qll index 06e95f715fb..144278727be 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class LinearFunctionExprBase extends @linear_function_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "LinearFunctionExpr" } + override string getAPrimaryQlClass() { result = "LinearFunctionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExtractOriginalExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExtractOriginalExpr.qll index b16b4a6a800..e03586daacc 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExtractOriginalExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/LinearFunctionExtractOriginalExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class LinearFunctionExtractOriginalExprBase extends @linear_function_extract_original_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "LinearFunctionExtractOriginalExpr" } + override string getAPrimaryQlClass() { result = "LinearFunctionExtractOriginalExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/LinearToDifferentiableFunctionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/LinearToDifferentiableFunctionExpr.qll index 6a9412cff81..e3bd9ae91b9 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/LinearToDifferentiableFunctionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/LinearToDifferentiableFunctionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class LinearToDifferentiableFunctionExprBase extends @linear_to_differentiable_function_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "LinearToDifferentiableFunctionExpr" } + override string getAPrimaryQlClass() { result = "LinearToDifferentiableFunctionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/LoadExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/LoadExpr.qll index 94e2e0419bb..89466753b9a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/LoadExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/LoadExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class LoadExprBase extends @load_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "LoadExpr" } + override string getAPrimaryQlClass() { result = "LoadExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/MagicIdentifierLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/MagicIdentifierLiteralExpr.qll index 8518d632bad..075cb1f955a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/MagicIdentifierLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/MagicIdentifierLiteralExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.BuiltinLiteralExpr class MagicIdentifierLiteralExprBase extends @magic_identifier_literal_expr, BuiltinLiteralExpr { - override string getPrimaryQlClass() { result = "MagicIdentifierLiteralExpr" } + override string getAPrimaryQlClass() { result = "MagicIdentifierLiteralExpr" } string getKind() { magic_identifier_literal_exprs(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/MakeTemporarilyEscapableExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/MakeTemporarilyEscapableExpr.qll index db856980eec..5fe0c7c829d 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/MakeTemporarilyEscapableExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/MakeTemporarilyEscapableExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.expr.OpaqueValueExpr class MakeTemporarilyEscapableExprBase extends @make_temporarily_escapable_expr, Expr { - override string getPrimaryQlClass() { result = "MakeTemporarilyEscapableExpr" } + override string getAPrimaryQlClass() { result = "MakeTemporarilyEscapableExpr" } OpaqueValueExpr getEscapingClosure() { exists(OpaqueValueExpr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/MemberRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/MemberRefExpr.qll index dc8dd448bf7..94bf0d6acf0 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/MemberRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/MemberRefExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.expr.LookupExpr class MemberRefExprBase extends @member_ref_expr, LookupExpr { - override string getPrimaryQlClass() { result = "MemberRefExpr" } + override string getAPrimaryQlClass() { result = "MemberRefExpr" } Expr getBaseExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/MetatypeConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/MetatypeConversionExpr.qll index 582ecef25ec..876074af22e 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/MetatypeConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/MetatypeConversionExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class MetatypeConversionExprBase extends @metatype_conversion_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "MetatypeConversionExpr" } + override string getAPrimaryQlClass() { result = "MetatypeConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/NilLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/NilLiteralExpr.qll index 8a5ec080b28..a0c78e7e567 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/NilLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/NilLiteralExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.LiteralExpr class NilLiteralExprBase extends @nil_literal_expr, LiteralExpr { - override string getPrimaryQlClass() { result = "NilLiteralExpr" } + override string getAPrimaryQlClass() { result = "NilLiteralExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ObjCSelectorExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ObjCSelectorExpr.qll index 1d2f0e9d3a5..9853878d1a2 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ObjCSelectorExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ObjCSelectorExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.decl.AbstractFunctionDecl import codeql.swift.elements.expr.Expr class ObjCSelectorExprBase extends @obj_c_selector_expr, Expr { - override string getPrimaryQlClass() { result = "ObjCSelectorExpr" } + override string getAPrimaryQlClass() { result = "ObjCSelectorExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/ObjectLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ObjectLiteralExpr.qll index b195bd9abc4..247c2cc3cf9 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ObjectLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ObjectLiteralExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.LiteralExpr class ObjectLiteralExprBase extends @object_literal_expr, LiteralExpr { - override string getPrimaryQlClass() { result = "ObjectLiteralExpr" } + override string getAPrimaryQlClass() { result = "ObjectLiteralExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/OneWayExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OneWayExpr.qll index 22cfa7726a7..4bebba18f26 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OneWayExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OneWayExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class OneWayExprBase extends @one_way_expr, Expr { - override string getPrimaryQlClass() { result = "OneWayExpr" } + override string getAPrimaryQlClass() { result = "OneWayExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/OpaqueValueExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OpaqueValueExpr.qll index ba56d0cf3ca..d88483fe6ab 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OpaqueValueExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OpaqueValueExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class OpaqueValueExprBase extends @opaque_value_expr, Expr { - override string getPrimaryQlClass() { result = "OpaqueValueExpr" } + override string getAPrimaryQlClass() { result = "OpaqueValueExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/OpenExistentialExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OpenExistentialExpr.qll index a8e8c335fd2..5ee0583013d 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OpenExistentialExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OpenExistentialExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.expr.OpaqueValueExpr class OpenExistentialExprBase extends @open_existential_expr, Expr { - override string getPrimaryQlClass() { result = "OpenExistentialExpr" } + override string getAPrimaryQlClass() { result = "OpenExistentialExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/OptionalEvaluationExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OptionalEvaluationExpr.qll index 1529d44ba6d..a4ae044d1a4 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OptionalEvaluationExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OptionalEvaluationExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class OptionalEvaluationExprBase extends @optional_evaluation_expr, Expr { - override string getPrimaryQlClass() { result = "OptionalEvaluationExpr" } + override string getAPrimaryQlClass() { result = "OptionalEvaluationExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/OptionalTryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OptionalTryExpr.qll index b62e6fd2865..fa11ff63a72 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OptionalTryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OptionalTryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.AnyTryExpr class OptionalTryExprBase extends @optional_try_expr, AnyTryExpr { - override string getPrimaryQlClass() { result = "OptionalTryExpr" } + override string getAPrimaryQlClass() { result = "OptionalTryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/OtherConstructorDeclRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OtherConstructorDeclRefExpr.qll index e4bf4398924..7d139c9b616 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OtherConstructorDeclRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OtherConstructorDeclRefExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class OtherConstructorDeclRefExprBase extends @other_constructor_decl_ref_expr, Expr { - override string getPrimaryQlClass() { result = "OtherConstructorDeclRefExpr" } + override string getAPrimaryQlClass() { result = "OtherConstructorDeclRefExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/OverloadedDeclRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/OverloadedDeclRefExpr.qll index 3e40c2810a3..96904abb628 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/OverloadedDeclRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/OverloadedDeclRefExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.OverloadSetRefExpr class OverloadedDeclRefExprBase extends @overloaded_decl_ref_expr, OverloadSetRefExpr { - override string getPrimaryQlClass() { result = "OverloadedDeclRefExpr" } + override string getAPrimaryQlClass() { result = "OverloadedDeclRefExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ParenExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ParenExpr.qll index f6b18942e02..c8e92eeea24 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ParenExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ParenExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.IdentityExpr class ParenExprBase extends @paren_expr, IdentityExpr { - override string getPrimaryQlClass() { result = "ParenExpr" } + override string getAPrimaryQlClass() { result = "ParenExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/PointerToPointerExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/PointerToPointerExpr.qll index 9e292a0eb04..dc81ee62119 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/PointerToPointerExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/PointerToPointerExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class PointerToPointerExprBase extends @pointer_to_pointer_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "PointerToPointerExpr" } + override string getAPrimaryQlClass() { result = "PointerToPointerExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/PostfixUnaryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/PostfixUnaryExpr.qll index 6be511150c7..4e3ffb93560 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/PostfixUnaryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/PostfixUnaryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ApplyExpr class PostfixUnaryExprBase extends @postfix_unary_expr, ApplyExpr { - override string getPrimaryQlClass() { result = "PostfixUnaryExpr" } + override string getAPrimaryQlClass() { result = "PostfixUnaryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/PrefixUnaryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/PrefixUnaryExpr.qll index ef31ea8acec..fcc0f15e3bd 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/PrefixUnaryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/PrefixUnaryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ApplyExpr class PrefixUnaryExprBase extends @prefix_unary_expr, ApplyExpr { - override string getPrimaryQlClass() { result = "PrefixUnaryExpr" } + override string getAPrimaryQlClass() { result = "PrefixUnaryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/PropertyWrapperValuePlaceholderExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/PropertyWrapperValuePlaceholderExpr.qll index 51407fef64b..786cca40bca 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/PropertyWrapperValuePlaceholderExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/PropertyWrapperValuePlaceholderExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class PropertyWrapperValuePlaceholderExprBase extends @property_wrapper_value_placeholder_expr, Expr { - override string getPrimaryQlClass() { result = "PropertyWrapperValuePlaceholderExpr" } + override string getAPrimaryQlClass() { result = "PropertyWrapperValuePlaceholderExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/ProtocolMetatypeToObjectExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/ProtocolMetatypeToObjectExpr.qll index 33426b7ab11..d09c67d83b3 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/ProtocolMetatypeToObjectExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/ProtocolMetatypeToObjectExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class ProtocolMetatypeToObjectExprBase extends @protocol_metatype_to_object_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "ProtocolMetatypeToObjectExpr" } + override string getAPrimaryQlClass() { result = "ProtocolMetatypeToObjectExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/RebindSelfInConstructorExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/RebindSelfInConstructorExpr.qll index 569160eb573..101a8c73b09 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/RebindSelfInConstructorExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/RebindSelfInConstructorExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.decl.VarDecl class RebindSelfInConstructorExprBase extends @rebind_self_in_constructor_expr, Expr { - override string getPrimaryQlClass() { result = "RebindSelfInConstructorExpr" } + override string getAPrimaryQlClass() { result = "RebindSelfInConstructorExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/RegexLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/RegexLiteralExpr.qll index 00d524b7f5c..ce4df9d13cb 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/RegexLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/RegexLiteralExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.LiteralExpr class RegexLiteralExprBase extends @regex_literal_expr, LiteralExpr { - override string getPrimaryQlClass() { result = "RegexLiteralExpr" } + override string getAPrimaryQlClass() { result = "RegexLiteralExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/SequenceExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/SequenceExpr.qll index 0b1397147a1..0361c393a72 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/SequenceExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/SequenceExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class SequenceExprBase extends @sequence_expr, Expr { - override string getPrimaryQlClass() { result = "SequenceExpr" } + override string getAPrimaryQlClass() { result = "SequenceExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/StringLiteralExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/StringLiteralExpr.qll index beb1a71c829..bb8e4174ad7 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/StringLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/StringLiteralExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.BuiltinLiteralExpr class StringLiteralExprBase extends @string_literal_expr, BuiltinLiteralExpr { - override string getPrimaryQlClass() { result = "StringLiteralExpr" } + override string getAPrimaryQlClass() { result = "StringLiteralExpr" } string getValue() { string_literal_exprs(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/StringToPointerExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/StringToPointerExpr.qll index 19553c9936a..ec679e974fb 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/StringToPointerExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/StringToPointerExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class StringToPointerExprBase extends @string_to_pointer_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "StringToPointerExpr" } + override string getAPrimaryQlClass() { result = "StringToPointerExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/SubscriptExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/SubscriptExpr.qll index 98e07ecd25b..cddbe8e8a2b 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/SubscriptExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/SubscriptExpr.qll @@ -5,7 +5,7 @@ import codeql.swift.elements.decl.GenericContext import codeql.swift.elements.expr.LookupExpr class SubscriptExprBase extends @subscript_expr, GenericContext, LookupExpr { - override string getPrimaryQlClass() { result = "SubscriptExpr" } + override string getAPrimaryQlClass() { result = "SubscriptExpr" } Expr getBaseExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/SuperRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/SuperRefExpr.qll index f8c6bfa740b..3513af5c0d7 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/SuperRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/SuperRefExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.decl.VarDecl class SuperRefExprBase extends @super_ref_expr, Expr { - override string getPrimaryQlClass() { result = "SuperRefExpr" } + override string getAPrimaryQlClass() { result = "SuperRefExpr" } VarDecl getSelf() { exists(VarDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/TapExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/TapExpr.qll index 1dfc2c39bce..a61533704e6 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/TapExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/TapExpr.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.decl.VarDecl class TapExprBase extends @tap_expr, Expr { - override string getPrimaryQlClass() { result = "TapExpr" } + override string getAPrimaryQlClass() { result = "TapExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/TryExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/TryExpr.qll index ccffde14675..2e14a85bd16 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/TryExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/TryExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.AnyTryExpr class TryExprBase extends @try_expr, AnyTryExpr { - override string getPrimaryQlClass() { result = "TryExpr" } + override string getAPrimaryQlClass() { result = "TryExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/TupleElementExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/TupleElementExpr.qll index 4f2e3b54a9c..4281d8d875c 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/TupleElementExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/TupleElementExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class TupleElementExprBase extends @tuple_element_expr, Expr { - override string getPrimaryQlClass() { result = "TupleElementExpr" } + override string getAPrimaryQlClass() { result = "TupleElementExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/TupleExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/TupleExpr.qll index 8024390f677..b985d64d111 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/TupleExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/TupleExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class TupleExprBase extends @tuple_expr, Expr { - override string getPrimaryQlClass() { result = "TupleExpr" } + override string getAPrimaryQlClass() { result = "TupleExpr" } Expr getElement(int index) { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/TypeExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/TypeExpr.qll index a26c599811c..8b9e238b3ca 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/TypeExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/TypeExpr.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.typerepr.TypeRepr class TypeExprBase extends @type_expr, Expr { - override string getPrimaryQlClass() { result = "TypeExpr" } + override string getAPrimaryQlClass() { result = "TypeExpr" } TypeRepr getTypeRepr() { exists(TypeRepr x | diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnderlyingToOpaqueExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnderlyingToOpaqueExpr.qll index 9a423be665f..314b404b11b 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnderlyingToOpaqueExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnderlyingToOpaqueExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class UnderlyingToOpaqueExprBase extends @underlying_to_opaque_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "UnderlyingToOpaqueExpr" } + override string getAPrimaryQlClass() { result = "UnderlyingToOpaqueExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnevaluatedInstanceExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnevaluatedInstanceExpr.qll index c64186f12ef..659f52e3fe2 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnevaluatedInstanceExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnevaluatedInstanceExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class UnevaluatedInstanceExprBase extends @unevaluated_instance_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "UnevaluatedInstanceExpr" } + override string getAPrimaryQlClass() { result = "UnevaluatedInstanceExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDeclRefExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDeclRefExpr.qll index 57a3e87d235..d30ac8d5d10 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDeclRefExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDeclRefExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class UnresolvedDeclRefExprBase extends @unresolved_decl_ref_expr, Expr { - override string getPrimaryQlClass() { result = "UnresolvedDeclRefExpr" } + override string getAPrimaryQlClass() { result = "UnresolvedDeclRefExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDotExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDotExpr.qll index 96db0e895ce..4aa821a1476 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDotExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedDotExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class UnresolvedDotExprBase extends @unresolved_dot_expr, Expr { - override string getPrimaryQlClass() { result = "UnresolvedDotExpr" } + override string getAPrimaryQlClass() { result = "UnresolvedDotExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberChainResultExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberChainResultExpr.qll index a2da6922c26..fde8b29000e 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberChainResultExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberChainResultExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.IdentityExpr class UnresolvedMemberChainResultExprBase extends @unresolved_member_chain_result_expr, IdentityExpr { - override string getPrimaryQlClass() { result = "UnresolvedMemberChainResultExpr" } + override string getAPrimaryQlClass() { result = "UnresolvedMemberChainResultExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberExpr.qll index 2d5f737f294..5cb908bdd18 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedMemberExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class UnresolvedMemberExprBase extends @unresolved_member_expr, Expr { - override string getPrimaryQlClass() { result = "UnresolvedMemberExpr" } + override string getAPrimaryQlClass() { result = "UnresolvedMemberExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedPatternExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedPatternExpr.qll index 5d2e88636c8..8d03b2079aa 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedPatternExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedPatternExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class UnresolvedPatternExprBase extends @unresolved_pattern_expr, Expr { - override string getPrimaryQlClass() { result = "UnresolvedPatternExpr" } + override string getAPrimaryQlClass() { result = "UnresolvedPatternExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedSpecializeExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedSpecializeExpr.qll index e61e89739b1..6109728e089 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedSpecializeExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedSpecializeExpr.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.expr.Expr class UnresolvedSpecializeExprBase extends @unresolved_specialize_expr, Expr { - override string getPrimaryQlClass() { result = "UnresolvedSpecializeExpr" } + override string getAPrimaryQlClass() { result = "UnresolvedSpecializeExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedTypeConversionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedTypeConversionExpr.qll index ac24c0426ad..fb4f5259c0a 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/UnresolvedTypeConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/UnresolvedTypeConversionExpr.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.expr.ImplicitConversionExpr class UnresolvedTypeConversionExprBase extends @unresolved_type_conversion_expr, ImplicitConversionExpr { - override string getPrimaryQlClass() { result = "UnresolvedTypeConversionExpr" } + override string getAPrimaryQlClass() { result = "UnresolvedTypeConversionExpr" } } diff --git a/swift/ql/lib/codeql/swift/generated/expr/VarargExpansionExpr.qll b/swift/ql/lib/codeql/swift/generated/expr/VarargExpansionExpr.qll index 6061852d7ca..b72261cf82f 100644 --- a/swift/ql/lib/codeql/swift/generated/expr/VarargExpansionExpr.qll +++ b/swift/ql/lib/codeql/swift/generated/expr/VarargExpansionExpr.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.expr.Expr class VarargExpansionExprBase extends @vararg_expansion_expr, Expr { - override string getPrimaryQlClass() { result = "VarargExpansionExpr" } + override string getAPrimaryQlClass() { result = "VarargExpansionExpr" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/AnyPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/AnyPattern.qll index f211968136c..d4349ccaa7e 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/AnyPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/AnyPattern.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.pattern.Pattern class AnyPatternBase extends @any_pattern, Pattern { - override string getPrimaryQlClass() { result = "AnyPattern" } + override string getAPrimaryQlClass() { result = "AnyPattern" } } diff --git a/swift/ql/lib/codeql/swift/generated/pattern/BindingPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/BindingPattern.qll index 748c71fddb8..0303ddab467 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/BindingPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/BindingPattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class BindingPatternBase extends @binding_pattern, Pattern { - override string getPrimaryQlClass() { result = "BindingPattern" } + override string getAPrimaryQlClass() { result = "BindingPattern" } Pattern getSubPattern() { exists(Pattern x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/BoolPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/BoolPattern.qll index cc4902320c4..2890e662e28 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/BoolPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/BoolPattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class BoolPatternBase extends @bool_pattern, Pattern { - override string getPrimaryQlClass() { result = "BoolPattern" } + override string getAPrimaryQlClass() { result = "BoolPattern" } boolean getValue() { bool_patterns(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/pattern/EnumElementPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/EnumElementPattern.qll index 1f9a27886b4..e0df35b15a0 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/EnumElementPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/EnumElementPattern.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.decl.EnumElementDecl import codeql.swift.elements.pattern.Pattern class EnumElementPatternBase extends @enum_element_pattern, Pattern { - override string getPrimaryQlClass() { result = "EnumElementPattern" } + override string getAPrimaryQlClass() { result = "EnumElementPattern" } EnumElementDecl getElement() { exists(EnumElementDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/ExprPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/ExprPattern.qll index 49946d7bc59..75fdb81cad9 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/ExprPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/ExprPattern.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.pattern.Pattern class ExprPatternBase extends @expr_pattern, Pattern { - override string getPrimaryQlClass() { result = "ExprPattern" } + override string getAPrimaryQlClass() { result = "ExprPattern" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/IsPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/IsPattern.qll index d491a253c28..8caf5493b36 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/IsPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/IsPattern.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.pattern.Pattern import codeql.swift.elements.typerepr.TypeRepr class IsPatternBase extends @is_pattern, Pattern { - override string getPrimaryQlClass() { result = "IsPattern" } + override string getAPrimaryQlClass() { result = "IsPattern" } TypeRepr getCastTypeRepr() { exists(TypeRepr x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/NamedPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/NamedPattern.qll index d7d43f0b738..a3d382fda9e 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/NamedPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/NamedPattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class NamedPatternBase extends @named_pattern, Pattern { - override string getPrimaryQlClass() { result = "NamedPattern" } + override string getAPrimaryQlClass() { result = "NamedPattern" } string getName() { named_patterns(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/pattern/OptionalSomePattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/OptionalSomePattern.qll index 0ca8700175b..3517777b9ce 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/OptionalSomePattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/OptionalSomePattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class OptionalSomePatternBase extends @optional_some_pattern, Pattern { - override string getPrimaryQlClass() { result = "OptionalSomePattern" } + override string getAPrimaryQlClass() { result = "OptionalSomePattern" } Pattern getSubPattern() { exists(Pattern x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/ParenPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/ParenPattern.qll index 815df89026c..63d5e2909ec 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/ParenPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/ParenPattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class ParenPatternBase extends @paren_pattern, Pattern { - override string getPrimaryQlClass() { result = "ParenPattern" } + override string getAPrimaryQlClass() { result = "ParenPattern" } Pattern getSubPattern() { exists(Pattern x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/TuplePattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/TuplePattern.qll index 86aad12c87d..b9eb01c83c9 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/TuplePattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/TuplePattern.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.pattern.Pattern class TuplePatternBase extends @tuple_pattern, Pattern { - override string getPrimaryQlClass() { result = "TuplePattern" } + override string getAPrimaryQlClass() { result = "TuplePattern" } Pattern getElement(int index) { exists(Pattern x | diff --git a/swift/ql/lib/codeql/swift/generated/pattern/TypedPattern.qll b/swift/ql/lib/codeql/swift/generated/pattern/TypedPattern.qll index 8eeb3f95744..9a16c9cfe02 100644 --- a/swift/ql/lib/codeql/swift/generated/pattern/TypedPattern.qll +++ b/swift/ql/lib/codeql/swift/generated/pattern/TypedPattern.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.pattern.Pattern import codeql.swift.elements.typerepr.TypeRepr class TypedPatternBase extends @typed_pattern, Pattern { - override string getPrimaryQlClass() { result = "TypedPattern" } + override string getAPrimaryQlClass() { result = "TypedPattern" } Pattern getSubPattern() { exists(Pattern x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/BraceStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/BraceStmt.qll index 4195c11a226..0cb37ff31bf 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/BraceStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/BraceStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.AstNode import codeql.swift.elements.stmt.Stmt class BraceStmtBase extends @brace_stmt, Stmt { - override string getPrimaryQlClass() { result = "BraceStmt" } + override string getAPrimaryQlClass() { result = "BraceStmt" } AstNode getElement(int index) { exists(AstNode x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/BreakStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/BreakStmt.qll index 34e6913e79d..05ba4de8fd3 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/BreakStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/BreakStmt.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.stmt.Stmt class BreakStmtBase extends @break_stmt, Stmt { - override string getPrimaryQlClass() { result = "BreakStmt" } + override string getAPrimaryQlClass() { result = "BreakStmt" } string getTargetName() { break_stmt_target_names(this, result) } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/CaseLabelItem.qll b/swift/ql/lib/codeql/swift/generated/stmt/CaseLabelItem.qll index 9f51f7da38f..f4f00f285b0 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/CaseLabelItem.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/CaseLabelItem.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.pattern.Pattern class CaseLabelItemBase extends @case_label_item, AstNode { - override string getPrimaryQlClass() { result = "CaseLabelItem" } + override string getAPrimaryQlClass() { result = "CaseLabelItem" } Pattern getPattern() { exists(Pattern x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/CaseStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/CaseStmt.qll index 738fca6ae43..d7111914429 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/CaseStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/CaseStmt.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.stmt.Stmt import codeql.swift.elements.decl.VarDecl class CaseStmtBase extends @case_stmt, Stmt { - override string getPrimaryQlClass() { result = "CaseStmt" } + override string getAPrimaryQlClass() { result = "CaseStmt" } Stmt getBody() { exists(Stmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/ConditionElement.qll b/swift/ql/lib/codeql/swift/generated/stmt/ConditionElement.qll index efde6e9a5e7..eb68c35bdf0 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/ConditionElement.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/ConditionElement.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.Locatable import codeql.swift.elements.pattern.Pattern class ConditionElementBase extends @condition_element, Locatable { - override string getPrimaryQlClass() { result = "ConditionElement" } + override string getAPrimaryQlClass() { result = "ConditionElement" } Expr getBoolean() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/ContinueStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/ContinueStmt.qll index 1c03ce6521b..10e6b2ac302 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/ContinueStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/ContinueStmt.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.stmt.Stmt class ContinueStmtBase extends @continue_stmt, Stmt { - override string getPrimaryQlClass() { result = "ContinueStmt" } + override string getAPrimaryQlClass() { result = "ContinueStmt" } string getTargetName() { continue_stmt_target_names(this, result) } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/DeferStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/DeferStmt.qll index 910b18c233d..7edd92fe917 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/DeferStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/DeferStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.BraceStmt import codeql.swift.elements.stmt.Stmt class DeferStmtBase extends @defer_stmt, Stmt { - override string getPrimaryQlClass() { result = "DeferStmt" } + override string getAPrimaryQlClass() { result = "DeferStmt" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/DoCatchStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/DoCatchStmt.qll index 56f8224b98a..7f98906d007 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/DoCatchStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/DoCatchStmt.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.stmt.LabeledStmt import codeql.swift.elements.stmt.Stmt class DoCatchStmtBase extends @do_catch_stmt, LabeledStmt { - override string getPrimaryQlClass() { result = "DoCatchStmt" } + override string getAPrimaryQlClass() { result = "DoCatchStmt" } Stmt getBody() { exists(Stmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/DoStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/DoStmt.qll index 7cfa724b1e6..f83646426e4 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/DoStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/DoStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.BraceStmt import codeql.swift.elements.stmt.LabeledStmt class DoStmtBase extends @do_stmt, LabeledStmt { - override string getPrimaryQlClass() { result = "DoStmt" } + override string getAPrimaryQlClass() { result = "DoStmt" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/FailStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/FailStmt.qll index dc5ce43c903..15f69def40d 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/FailStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/FailStmt.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.stmt.Stmt class FailStmtBase extends @fail_stmt, Stmt { - override string getPrimaryQlClass() { result = "FailStmt" } + override string getAPrimaryQlClass() { result = "FailStmt" } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/FallthroughStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/FallthroughStmt.qll index 1adfbbd972f..5faaac0ad9b 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/FallthroughStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/FallthroughStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.CaseStmt import codeql.swift.elements.stmt.Stmt class FallthroughStmtBase extends @fallthrough_stmt, Stmt { - override string getPrimaryQlClass() { result = "FallthroughStmt" } + override string getAPrimaryQlClass() { result = "FallthroughStmt" } CaseStmt getFallthroughSource() { exists(CaseStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/ForEachStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/ForEachStmt.qll index ad1fb14ee8e..f75e0a6f08b 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/ForEachStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/ForEachStmt.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.stmt.LabeledStmt class ForEachStmtBase extends @for_each_stmt, LabeledStmt { - override string getPrimaryQlClass() { result = "ForEachStmt" } + override string getAPrimaryQlClass() { result = "ForEachStmt" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/GuardStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/GuardStmt.qll index 933bd56b2df..7ce5fae33a2 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/GuardStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/GuardStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.BraceStmt import codeql.swift.elements.stmt.LabeledConditionalStmt class GuardStmtBase extends @guard_stmt, LabeledConditionalStmt { - override string getPrimaryQlClass() { result = "GuardStmt" } + override string getAPrimaryQlClass() { result = "GuardStmt" } BraceStmt getBody() { exists(BraceStmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/IfStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/IfStmt.qll index 381c2cc9097..4311173fe51 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/IfStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/IfStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.LabeledConditionalStmt import codeql.swift.elements.stmt.Stmt class IfStmtBase extends @if_stmt, LabeledConditionalStmt { - override string getPrimaryQlClass() { result = "IfStmt" } + override string getAPrimaryQlClass() { result = "IfStmt" } Stmt getThen() { exists(Stmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/PoundAssertStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/PoundAssertStmt.qll index 9538899c285..afbd1ffdf13 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/PoundAssertStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/PoundAssertStmt.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.stmt.Stmt class PoundAssertStmtBase extends @pound_assert_stmt, Stmt { - override string getPrimaryQlClass() { result = "PoundAssertStmt" } + override string getAPrimaryQlClass() { result = "PoundAssertStmt" } } diff --git a/swift/ql/lib/codeql/swift/generated/stmt/RepeatWhileStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/RepeatWhileStmt.qll index 688847947c8..6d03dcc07a9 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/RepeatWhileStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/RepeatWhileStmt.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.stmt.LabeledStmt import codeql.swift.elements.stmt.Stmt class RepeatWhileStmtBase extends @repeat_while_stmt, LabeledStmt { - override string getPrimaryQlClass() { result = "RepeatWhileStmt" } + override string getAPrimaryQlClass() { result = "RepeatWhileStmt" } Expr getCondition() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/ReturnStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/ReturnStmt.qll index 167d1795d19..dcdaaae19b6 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/ReturnStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/ReturnStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.stmt.Stmt class ReturnStmtBase extends @return_stmt, Stmt { - override string getPrimaryQlClass() { result = "ReturnStmt" } + override string getAPrimaryQlClass() { result = "ReturnStmt" } Expr getResult() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/StmtCondition.qll b/swift/ql/lib/codeql/swift/generated/stmt/StmtCondition.qll index 19e0614f192..94aa0b746d2 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/StmtCondition.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/StmtCondition.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.AstNode import codeql.swift.elements.stmt.ConditionElement class StmtConditionBase extends @stmt_condition, AstNode { - override string getPrimaryQlClass() { result = "StmtCondition" } + override string getAPrimaryQlClass() { result = "StmtCondition" } ConditionElement getElement(int index) { exists(ConditionElement x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/SwitchStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/SwitchStmt.qll index 9bc1223aa59..79bd3116cfe 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/SwitchStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/SwitchStmt.qll @@ -4,7 +4,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.stmt.LabeledStmt class SwitchStmtBase extends @switch_stmt, LabeledStmt { - override string getPrimaryQlClass() { result = "SwitchStmt" } + override string getAPrimaryQlClass() { result = "SwitchStmt" } Expr getExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/ThrowStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/ThrowStmt.qll index 5d542ced5b0..7ede67545bb 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/ThrowStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/ThrowStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.expr.Expr import codeql.swift.elements.stmt.Stmt class ThrowStmtBase extends @throw_stmt, Stmt { - override string getPrimaryQlClass() { result = "ThrowStmt" } + override string getAPrimaryQlClass() { result = "ThrowStmt" } Expr getSubExpr() { exists(Expr x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/WhileStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/WhileStmt.qll index e4a197593d6..959a129834b 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/WhileStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/WhileStmt.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.stmt.LabeledConditionalStmt import codeql.swift.elements.stmt.Stmt class WhileStmtBase extends @while_stmt, LabeledConditionalStmt { - override string getPrimaryQlClass() { result = "WhileStmt" } + override string getAPrimaryQlClass() { result = "WhileStmt" } Stmt getBody() { exists(Stmt x | diff --git a/swift/ql/lib/codeql/swift/generated/stmt/YieldStmt.qll b/swift/ql/lib/codeql/swift/generated/stmt/YieldStmt.qll index 544fdd9751e..4cc32d764e1 100644 --- a/swift/ql/lib/codeql/swift/generated/stmt/YieldStmt.qll +++ b/swift/ql/lib/codeql/swift/generated/stmt/YieldStmt.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.stmt.Stmt class YieldStmtBase extends @yield_stmt, Stmt { - override string getPrimaryQlClass() { result = "YieldStmt" } + override string getAPrimaryQlClass() { result = "YieldStmt" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ArraySliceType.qll b/swift/ql/lib/codeql/swift/generated/type/ArraySliceType.qll index 2b029e0f741..bb132bc2c72 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ArraySliceType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ArraySliceType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.UnarySyntaxSugarType class ArraySliceTypeBase extends @array_slice_type, UnarySyntaxSugarType { - override string getPrimaryQlClass() { result = "ArraySliceType" } + override string getAPrimaryQlClass() { result = "ArraySliceType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BoundGenericClassType.qll b/swift/ql/lib/codeql/swift/generated/type/BoundGenericClassType.qll index d7bf09fddd2..3d2a78b2309 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BoundGenericClassType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BoundGenericClassType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BoundGenericType class BoundGenericClassTypeBase extends @bound_generic_class_type, BoundGenericType { - override string getPrimaryQlClass() { result = "BoundGenericClassType" } + override string getAPrimaryQlClass() { result = "BoundGenericClassType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BoundGenericEnumType.qll b/swift/ql/lib/codeql/swift/generated/type/BoundGenericEnumType.qll index e73f964c395..57103dce7f7 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BoundGenericEnumType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BoundGenericEnumType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BoundGenericType class BoundGenericEnumTypeBase extends @bound_generic_enum_type, BoundGenericType { - override string getPrimaryQlClass() { result = "BoundGenericEnumType" } + override string getAPrimaryQlClass() { result = "BoundGenericEnumType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BoundGenericStructType.qll b/swift/ql/lib/codeql/swift/generated/type/BoundGenericStructType.qll index 1b7a82b165a..2f5d514488a 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BoundGenericStructType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BoundGenericStructType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BoundGenericType class BoundGenericStructTypeBase extends @bound_generic_struct_type, BoundGenericType { - override string getPrimaryQlClass() { result = "BoundGenericStructType" } + override string getAPrimaryQlClass() { result = "BoundGenericStructType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinBridgeObjectType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinBridgeObjectType.qll index d9d99ea7621..8e18276ef2c 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinBridgeObjectType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinBridgeObjectType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinBridgeObjectTypeBase extends @builtin_bridge_object_type, BuiltinType { - override string getPrimaryQlClass() { result = "BuiltinBridgeObjectType" } + override string getAPrimaryQlClass() { result = "BuiltinBridgeObjectType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinDefaultActorStorageType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinDefaultActorStorageType.qll index 88766c8a91b..cdc635f42a7 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinDefaultActorStorageType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinDefaultActorStorageType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinDefaultActorStorageTypeBase extends @builtin_default_actor_storage_type, BuiltinType { - override string getPrimaryQlClass() { result = "BuiltinDefaultActorStorageType" } + override string getAPrimaryQlClass() { result = "BuiltinDefaultActorStorageType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinExecutorType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinExecutorType.qll index fb49989bf5e..32444cc4704 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinExecutorType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinExecutorType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinExecutorTypeBase extends @builtin_executor_type, BuiltinType { - override string getPrimaryQlClass() { result = "BuiltinExecutorType" } + override string getAPrimaryQlClass() { result = "BuiltinExecutorType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinFloatType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinFloatType.qll index 32b1244b0ef..509e66a070c 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinFloatType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinFloatType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinFloatTypeBase extends @builtin_float_type, BuiltinType { - override string getPrimaryQlClass() { result = "BuiltinFloatType" } + override string getAPrimaryQlClass() { result = "BuiltinFloatType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerLiteralType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerLiteralType.qll index 2e61b1008cf..88c8b0dd3db 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerLiteralType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerLiteralType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyBuiltinIntegerType class BuiltinIntegerLiteralTypeBase extends @builtin_integer_literal_type, AnyBuiltinIntegerType { - override string getPrimaryQlClass() { result = "BuiltinIntegerLiteralType" } + override string getAPrimaryQlClass() { result = "BuiltinIntegerLiteralType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerType.qll index eaeb8656e7d..a725a9001c3 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinIntegerType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyBuiltinIntegerType class BuiltinIntegerTypeBase extends @builtin_integer_type, AnyBuiltinIntegerType { - override string getPrimaryQlClass() { result = "BuiltinIntegerType" } + override string getAPrimaryQlClass() { result = "BuiltinIntegerType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinJobType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinJobType.qll index f2e8fc76c73..4f89a9a02c2 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinJobType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinJobType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinJobTypeBase extends @builtin_job_type, BuiltinType { - override string getPrimaryQlClass() { result = "BuiltinJobType" } + override string getAPrimaryQlClass() { result = "BuiltinJobType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinNativeObjectType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinNativeObjectType.qll index 6382b94bc1b..26d84273d89 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinNativeObjectType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinNativeObjectType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinNativeObjectTypeBase extends @builtin_native_object_type, BuiltinType { - override string getPrimaryQlClass() { result = "BuiltinNativeObjectType" } + override string getAPrimaryQlClass() { result = "BuiltinNativeObjectType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinRawPointerType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinRawPointerType.qll index f56d5921d30..509f0eddba6 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinRawPointerType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinRawPointerType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinRawPointerTypeBase extends @builtin_raw_pointer_type, BuiltinType { - override string getPrimaryQlClass() { result = "BuiltinRawPointerType" } + override string getAPrimaryQlClass() { result = "BuiltinRawPointerType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinRawUnsafeContinuationType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinRawUnsafeContinuationType.qll index d9edb49d4b3..4fd93326e5e 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinRawUnsafeContinuationType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinRawUnsafeContinuationType.qll @@ -3,5 +3,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinRawUnsafeContinuationTypeBase extends @builtin_raw_unsafe_continuation_type, BuiltinType { - override string getPrimaryQlClass() { result = "BuiltinRawUnsafeContinuationType" } + override string getAPrimaryQlClass() { result = "BuiltinRawUnsafeContinuationType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinUnsafeValueBufferType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinUnsafeValueBufferType.qll index 02e200cb39e..76f2beb8d95 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinUnsafeValueBufferType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinUnsafeValueBufferType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinUnsafeValueBufferTypeBase extends @builtin_unsafe_value_buffer_type, BuiltinType { - override string getPrimaryQlClass() { result = "BuiltinUnsafeValueBufferType" } + override string getAPrimaryQlClass() { result = "BuiltinUnsafeValueBufferType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/BuiltinVectorType.qll b/swift/ql/lib/codeql/swift/generated/type/BuiltinVectorType.qll index 3c1b612470f..493a64f7717 100644 --- a/swift/ql/lib/codeql/swift/generated/type/BuiltinVectorType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/BuiltinVectorType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.BuiltinType class BuiltinVectorTypeBase extends @builtin_vector_type, BuiltinType { - override string getPrimaryQlClass() { result = "BuiltinVectorType" } + override string getAPrimaryQlClass() { result = "BuiltinVectorType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ClassType.qll b/swift/ql/lib/codeql/swift/generated/type/ClassType.qll index 5fbb1ea181c..377bf3dc4d3 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ClassType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ClassType.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.decl.ClassDecl import codeql.swift.elements.type.NominalType class ClassTypeBase extends @class_type, NominalType { - override string getPrimaryQlClass() { result = "ClassType" } + override string getAPrimaryQlClass() { result = "ClassType" } ClassDecl getDecl() { exists(ClassDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/type/DependentMemberType.qll b/swift/ql/lib/codeql/swift/generated/type/DependentMemberType.qll index 9724322349c..e7cc3141023 100644 --- a/swift/ql/lib/codeql/swift/generated/type/DependentMemberType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/DependentMemberType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class DependentMemberTypeBase extends @dependent_member_type, Type { - override string getPrimaryQlClass() { result = "DependentMemberType" } + override string getAPrimaryQlClass() { result = "DependentMemberType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/DictionaryType.qll b/swift/ql/lib/codeql/swift/generated/type/DictionaryType.qll index 8c469221d6d..8fa8ea3cdf6 100644 --- a/swift/ql/lib/codeql/swift/generated/type/DictionaryType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/DictionaryType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.SyntaxSugarType class DictionaryTypeBase extends @dictionary_type, SyntaxSugarType { - override string getPrimaryQlClass() { result = "DictionaryType" } + override string getAPrimaryQlClass() { result = "DictionaryType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/DynamicSelfType.qll b/swift/ql/lib/codeql/swift/generated/type/DynamicSelfType.qll index cc1bd77d0ca..ff3eeb90b87 100644 --- a/swift/ql/lib/codeql/swift/generated/type/DynamicSelfType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/DynamicSelfType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class DynamicSelfTypeBase extends @dynamic_self_type, Type { - override string getPrimaryQlClass() { result = "DynamicSelfType" } + override string getAPrimaryQlClass() { result = "DynamicSelfType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/EnumType.qll b/swift/ql/lib/codeql/swift/generated/type/EnumType.qll index 67b35b77327..99e2cea2fcd 100644 --- a/swift/ql/lib/codeql/swift/generated/type/EnumType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/EnumType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.NominalType class EnumTypeBase extends @enum_type, NominalType { - override string getPrimaryQlClass() { result = "EnumType" } + override string getAPrimaryQlClass() { result = "EnumType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ErrorType.qll b/swift/ql/lib/codeql/swift/generated/type/ErrorType.qll index 9ca5121caba..f7156ec110c 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ErrorType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ErrorType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class ErrorTypeBase extends @error_type, Type { - override string getPrimaryQlClass() { result = "ErrorType" } + override string getAPrimaryQlClass() { result = "ErrorType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ExistentialMetatypeType.qll b/swift/ql/lib/codeql/swift/generated/type/ExistentialMetatypeType.qll index f833a4ecb9c..fcdd1a52224 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ExistentialMetatypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ExistentialMetatypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyMetatypeType class ExistentialMetatypeTypeBase extends @existential_metatype_type, AnyMetatypeType { - override string getPrimaryQlClass() { result = "ExistentialMetatypeType" } + override string getAPrimaryQlClass() { result = "ExistentialMetatypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ExistentialType.qll b/swift/ql/lib/codeql/swift/generated/type/ExistentialType.qll index 349c5f2cd64..e2d92d553de 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ExistentialType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ExistentialType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class ExistentialTypeBase extends @existential_type, Type { - override string getPrimaryQlClass() { result = "ExistentialType" } + override string getAPrimaryQlClass() { result = "ExistentialType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/FunctionType.qll b/swift/ql/lib/codeql/swift/generated/type/FunctionType.qll index e5bd2a38e61..dcb5da46bbd 100644 --- a/swift/ql/lib/codeql/swift/generated/type/FunctionType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/FunctionType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyFunctionType class FunctionTypeBase extends @function_type, AnyFunctionType { - override string getPrimaryQlClass() { result = "FunctionType" } + override string getAPrimaryQlClass() { result = "FunctionType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/GenericFunctionType.qll b/swift/ql/lib/codeql/swift/generated/type/GenericFunctionType.qll index 2094eabead8..7b34e262d03 100644 --- a/swift/ql/lib/codeql/swift/generated/type/GenericFunctionType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/GenericFunctionType.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.type.AnyFunctionType import codeql.swift.elements.type.GenericTypeParamType class GenericFunctionTypeBase extends @generic_function_type, AnyFunctionType { - override string getPrimaryQlClass() { result = "GenericFunctionType" } + override string getAPrimaryQlClass() { result = "GenericFunctionType" } GenericTypeParamType getGenericParam(int index) { exists(GenericTypeParamType x | diff --git a/swift/ql/lib/codeql/swift/generated/type/GenericTypeParamType.qll b/swift/ql/lib/codeql/swift/generated/type/GenericTypeParamType.qll index 848b6ca728e..c0b13904806 100644 --- a/swift/ql/lib/codeql/swift/generated/type/GenericTypeParamType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/GenericTypeParamType.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.type.SubstitutableType class GenericTypeParamTypeBase extends @generic_type_param_type, SubstitutableType { - override string getPrimaryQlClass() { result = "GenericTypeParamType" } + override string getAPrimaryQlClass() { result = "GenericTypeParamType" } string getName() { generic_type_param_types(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/type/InOutType.qll b/swift/ql/lib/codeql/swift/generated/type/InOutType.qll index dc0ed86c0f6..4d54e929657 100644 --- a/swift/ql/lib/codeql/swift/generated/type/InOutType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/InOutType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class InOutTypeBase extends @in_out_type, Type { - override string getPrimaryQlClass() { result = "InOutType" } + override string getAPrimaryQlClass() { result = "InOutType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/LValueType.qll b/swift/ql/lib/codeql/swift/generated/type/LValueType.qll index abba3937ddc..df0f433ac84 100644 --- a/swift/ql/lib/codeql/swift/generated/type/LValueType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/LValueType.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.type.Type class LValueTypeBase extends @l_value_type, Type { - override string getPrimaryQlClass() { result = "LValueType" } + override string getAPrimaryQlClass() { result = "LValueType" } Type getObjectType() { exists(Type x | diff --git a/swift/ql/lib/codeql/swift/generated/type/MetatypeType.qll b/swift/ql/lib/codeql/swift/generated/type/MetatypeType.qll index 73ecd90e57d..e6663f3b357 100644 --- a/swift/ql/lib/codeql/swift/generated/type/MetatypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/MetatypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyMetatypeType class MetatypeTypeBase extends @metatype_type, AnyMetatypeType { - override string getPrimaryQlClass() { result = "MetatypeType" } + override string getAPrimaryQlClass() { result = "MetatypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ModuleType.qll b/swift/ql/lib/codeql/swift/generated/type/ModuleType.qll index d3930e98f16..91da39854d7 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ModuleType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ModuleType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class ModuleTypeBase extends @module_type, Type { - override string getPrimaryQlClass() { result = "ModuleType" } + override string getAPrimaryQlClass() { result = "ModuleType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/NestedArchetypeType.qll b/swift/ql/lib/codeql/swift/generated/type/NestedArchetypeType.qll index dcbc5e37382..7306e294785 100644 --- a/swift/ql/lib/codeql/swift/generated/type/NestedArchetypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/NestedArchetypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ArchetypeType class NestedArchetypeTypeBase extends @nested_archetype_type, ArchetypeType { - override string getPrimaryQlClass() { result = "NestedArchetypeType" } + override string getAPrimaryQlClass() { result = "NestedArchetypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/OpaqueTypeArchetypeType.qll b/swift/ql/lib/codeql/swift/generated/type/OpaqueTypeArchetypeType.qll index a891f5fa01c..c0a1f637f3c 100644 --- a/swift/ql/lib/codeql/swift/generated/type/OpaqueTypeArchetypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/OpaqueTypeArchetypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ArchetypeType class OpaqueTypeArchetypeTypeBase extends @opaque_type_archetype_type, ArchetypeType { - override string getPrimaryQlClass() { result = "OpaqueTypeArchetypeType" } + override string getAPrimaryQlClass() { result = "OpaqueTypeArchetypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/OpenedArchetypeType.qll b/swift/ql/lib/codeql/swift/generated/type/OpenedArchetypeType.qll index 8060c387cb3..2d723dfb10d 100644 --- a/swift/ql/lib/codeql/swift/generated/type/OpenedArchetypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/OpenedArchetypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ArchetypeType class OpenedArchetypeTypeBase extends @opened_archetype_type, ArchetypeType { - override string getPrimaryQlClass() { result = "OpenedArchetypeType" } + override string getAPrimaryQlClass() { result = "OpenedArchetypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/OptionalType.qll b/swift/ql/lib/codeql/swift/generated/type/OptionalType.qll index 6a9002753ae..a814cf4d002 100644 --- a/swift/ql/lib/codeql/swift/generated/type/OptionalType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/OptionalType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.UnarySyntaxSugarType class OptionalTypeBase extends @optional_type, UnarySyntaxSugarType { - override string getPrimaryQlClass() { result = "OptionalType" } + override string getAPrimaryQlClass() { result = "OptionalType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ParenType.qll b/swift/ql/lib/codeql/swift/generated/type/ParenType.qll index a1124af7033..036a551f4e4 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ParenType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ParenType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.SugarType class ParenTypeBase extends @paren_type, SugarType { - override string getPrimaryQlClass() { result = "ParenType" } + override string getAPrimaryQlClass() { result = "ParenType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/PlaceholderType.qll b/swift/ql/lib/codeql/swift/generated/type/PlaceholderType.qll index 7f5e292d326..134bdb7a6c8 100644 --- a/swift/ql/lib/codeql/swift/generated/type/PlaceholderType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/PlaceholderType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class PlaceholderTypeBase extends @placeholder_type, Type { - override string getPrimaryQlClass() { result = "PlaceholderType" } + override string getAPrimaryQlClass() { result = "PlaceholderType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/PrimaryArchetypeType.qll b/swift/ql/lib/codeql/swift/generated/type/PrimaryArchetypeType.qll index 2790cad235c..6f062e05799 100644 --- a/swift/ql/lib/codeql/swift/generated/type/PrimaryArchetypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/PrimaryArchetypeType.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.type.ArchetypeType import codeql.swift.elements.type.GenericTypeParamType class PrimaryArchetypeTypeBase extends @primary_archetype_type, ArchetypeType { - override string getPrimaryQlClass() { result = "PrimaryArchetypeType" } + override string getAPrimaryQlClass() { result = "PrimaryArchetypeType" } GenericTypeParamType getInterfaceType() { exists(GenericTypeParamType x | diff --git a/swift/ql/lib/codeql/swift/generated/type/ProtocolCompositionType.qll b/swift/ql/lib/codeql/swift/generated/type/ProtocolCompositionType.qll index 05f1e2217b2..863f8c8ca8b 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ProtocolCompositionType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ProtocolCompositionType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class ProtocolCompositionTypeBase extends @protocol_composition_type, Type { - override string getPrimaryQlClass() { result = "ProtocolCompositionType" } + override string getAPrimaryQlClass() { result = "ProtocolCompositionType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/ProtocolType.qll b/swift/ql/lib/codeql/swift/generated/type/ProtocolType.qll index 1550e83b488..9f157eb06ef 100644 --- a/swift/ql/lib/codeql/swift/generated/type/ProtocolType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/ProtocolType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.NominalType class ProtocolTypeBase extends @protocol_type, NominalType { - override string getPrimaryQlClass() { result = "ProtocolType" } + override string getAPrimaryQlClass() { result = "ProtocolType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/SequenceArchetypeType.qll b/swift/ql/lib/codeql/swift/generated/type/SequenceArchetypeType.qll index 289a2e353a9..08a9350d9ac 100644 --- a/swift/ql/lib/codeql/swift/generated/type/SequenceArchetypeType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/SequenceArchetypeType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ArchetypeType class SequenceArchetypeTypeBase extends @sequence_archetype_type, ArchetypeType { - override string getPrimaryQlClass() { result = "SequenceArchetypeType" } + override string getAPrimaryQlClass() { result = "SequenceArchetypeType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/SilBlockStorageType.qll b/swift/ql/lib/codeql/swift/generated/type/SilBlockStorageType.qll index 2743a47444d..185652e2e8a 100644 --- a/swift/ql/lib/codeql/swift/generated/type/SilBlockStorageType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/SilBlockStorageType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class SilBlockStorageTypeBase extends @sil_block_storage_type, Type { - override string getPrimaryQlClass() { result = "SilBlockStorageType" } + override string getAPrimaryQlClass() { result = "SilBlockStorageType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/SilBoxType.qll b/swift/ql/lib/codeql/swift/generated/type/SilBoxType.qll index 26d6ef84f3b..5a879026ef3 100644 --- a/swift/ql/lib/codeql/swift/generated/type/SilBoxType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/SilBoxType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class SilBoxTypeBase extends @sil_box_type, Type { - override string getPrimaryQlClass() { result = "SilBoxType" } + override string getAPrimaryQlClass() { result = "SilBoxType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/SilFunctionType.qll b/swift/ql/lib/codeql/swift/generated/type/SilFunctionType.qll index 2299a4ea753..103e80dddf1 100644 --- a/swift/ql/lib/codeql/swift/generated/type/SilFunctionType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/SilFunctionType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class SilFunctionTypeBase extends @sil_function_type, Type { - override string getPrimaryQlClass() { result = "SilFunctionType" } + override string getAPrimaryQlClass() { result = "SilFunctionType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/SilTokenType.qll b/swift/ql/lib/codeql/swift/generated/type/SilTokenType.qll index ed988b86014..50582c2b761 100644 --- a/swift/ql/lib/codeql/swift/generated/type/SilTokenType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/SilTokenType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class SilTokenTypeBase extends @sil_token_type, Type { - override string getPrimaryQlClass() { result = "SilTokenType" } + override string getAPrimaryQlClass() { result = "SilTokenType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/StructType.qll b/swift/ql/lib/codeql/swift/generated/type/StructType.qll index 3d23e210c59..fedb9024bfb 100644 --- a/swift/ql/lib/codeql/swift/generated/type/StructType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/StructType.qll @@ -3,7 +3,7 @@ import codeql.swift.elements.type.NominalType import codeql.swift.elements.decl.StructDecl class StructTypeBase extends @struct_type, NominalType { - override string getPrimaryQlClass() { result = "StructType" } + override string getAPrimaryQlClass() { result = "StructType" } StructDecl getDecl() { exists(StructDecl x | diff --git a/swift/ql/lib/codeql/swift/generated/type/TupleType.qll b/swift/ql/lib/codeql/swift/generated/type/TupleType.qll index ba5b4c50e2c..15250bdaf9d 100644 --- a/swift/ql/lib/codeql/swift/generated/type/TupleType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/TupleType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class TupleTypeBase extends @tuple_type, Type { - override string getPrimaryQlClass() { result = "TupleType" } + override string getAPrimaryQlClass() { result = "TupleType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/TypeAliasType.qll b/swift/ql/lib/codeql/swift/generated/type/TypeAliasType.qll index e5a5d8d5aba..595b20e0cfe 100644 --- a/swift/ql/lib/codeql/swift/generated/type/TypeAliasType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/TypeAliasType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.SugarType class TypeAliasTypeBase extends @type_alias_type, SugarType { - override string getPrimaryQlClass() { result = "TypeAliasType" } + override string getAPrimaryQlClass() { result = "TypeAliasType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/TypeVariableType.qll b/swift/ql/lib/codeql/swift/generated/type/TypeVariableType.qll index 0714a59f039..c6c82c1e982 100644 --- a/swift/ql/lib/codeql/swift/generated/type/TypeVariableType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/TypeVariableType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class TypeVariableTypeBase extends @type_variable_type, Type { - override string getPrimaryQlClass() { result = "TypeVariableType" } + override string getAPrimaryQlClass() { result = "TypeVariableType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/UnboundGenericType.qll b/swift/ql/lib/codeql/swift/generated/type/UnboundGenericType.qll index 4d64e72720f..b4946cea77d 100644 --- a/swift/ql/lib/codeql/swift/generated/type/UnboundGenericType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/UnboundGenericType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.AnyGenericType class UnboundGenericTypeBase extends @unbound_generic_type, AnyGenericType { - override string getPrimaryQlClass() { result = "UnboundGenericType" } + override string getAPrimaryQlClass() { result = "UnboundGenericType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/UnknownType.qll b/swift/ql/lib/codeql/swift/generated/type/UnknownType.qll index 9b3fe7eb0c0..220f9e44370 100644 --- a/swift/ql/lib/codeql/swift/generated/type/UnknownType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/UnknownType.qll @@ -2,7 +2,7 @@ import codeql.swift.elements.type.Type class UnknownTypeBase extends @unknown_type, Type { - override string getPrimaryQlClass() { result = "UnknownType" } + override string getAPrimaryQlClass() { result = "UnknownType" } string getName() { unknown_types(this, result) } } diff --git a/swift/ql/lib/codeql/swift/generated/type/UnmanagedStorageType.qll b/swift/ql/lib/codeql/swift/generated/type/UnmanagedStorageType.qll index 3171a6aec32..def9e7be671 100644 --- a/swift/ql/lib/codeql/swift/generated/type/UnmanagedStorageType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/UnmanagedStorageType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ReferenceStorageType class UnmanagedStorageTypeBase extends @unmanaged_storage_type, ReferenceStorageType { - override string getPrimaryQlClass() { result = "UnmanagedStorageType" } + override string getAPrimaryQlClass() { result = "UnmanagedStorageType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/UnownedStorageType.qll b/swift/ql/lib/codeql/swift/generated/type/UnownedStorageType.qll index 6e3c2f1bd23..3a8b60c19b0 100644 --- a/swift/ql/lib/codeql/swift/generated/type/UnownedStorageType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/UnownedStorageType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ReferenceStorageType class UnownedStorageTypeBase extends @unowned_storage_type, ReferenceStorageType { - override string getPrimaryQlClass() { result = "UnownedStorageType" } + override string getAPrimaryQlClass() { result = "UnownedStorageType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/UnresolvedType.qll b/swift/ql/lib/codeql/swift/generated/type/UnresolvedType.qll index a88083914ef..a5a5abb4d91 100644 --- a/swift/ql/lib/codeql/swift/generated/type/UnresolvedType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/UnresolvedType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.Type class UnresolvedTypeBase extends @unresolved_type, Type { - override string getPrimaryQlClass() { result = "UnresolvedType" } + override string getAPrimaryQlClass() { result = "UnresolvedType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/VariadicSequenceType.qll b/swift/ql/lib/codeql/swift/generated/type/VariadicSequenceType.qll index 38c85d12a5e..18ad64789df 100644 --- a/swift/ql/lib/codeql/swift/generated/type/VariadicSequenceType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/VariadicSequenceType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.UnarySyntaxSugarType class VariadicSequenceTypeBase extends @variadic_sequence_type, UnarySyntaxSugarType { - override string getPrimaryQlClass() { result = "VariadicSequenceType" } + override string getAPrimaryQlClass() { result = "VariadicSequenceType" } } diff --git a/swift/ql/lib/codeql/swift/generated/type/WeakStorageType.qll b/swift/ql/lib/codeql/swift/generated/type/WeakStorageType.qll index 3adb449b4bc..ce6a8837816 100644 --- a/swift/ql/lib/codeql/swift/generated/type/WeakStorageType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/WeakStorageType.qll @@ -2,5 +2,5 @@ import codeql.swift.elements.type.ReferenceStorageType class WeakStorageTypeBase extends @weak_storage_type, ReferenceStorageType { - override string getPrimaryQlClass() { result = "WeakStorageType" } + override string getAPrimaryQlClass() { result = "WeakStorageType" } } From 7c10f3e76bc08b4319fa78d230367d19024dfef6 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 10 May 2022 14:38:53 +0000 Subject: [PATCH 163/171] C#: Lua tracing config: Use API function. --- csharp/tools/tracing-config.lua | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/csharp/tools/tracing-config.lua b/csharp/tools/tracing-config.lua index 77d69beb6b1..f0b7b67f46d 100644 --- a/csharp/tools/tracing-config.lua +++ b/csharp/tools/tracing-config.lua @@ -1,4 +1,4 @@ -function RegisterExtractorPack() +function RegisterExtractorPack(id) local extractor = GetPlatformToolsDirectory() .. 'Semmle.Extraction.CSharp.Driver' if OperatingSystem == 'windows' then extractor = extractor .. '.exe' end @@ -26,14 +26,10 @@ function RegisterExtractorPack() return { replace = true, invocations = { - { - path = compilerPath, - transformedArguments = { - nativeArgumentPointer = compilerArguments['nativeArgumentPointer'], - append = {'/p:UseSharedCompilation=false'}, - prepend = {} - } - } + BuildExtractorInvocation(id, compilerPath, compilerPath, + compilerArguments, nil, { + '/p:UseSharedCompilation=false' + }) } } end From a5acaeb59ce5e932e78e7b5d09747d00becf0cbb Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 10 May 2022 23:25:32 +0200 Subject: [PATCH 164/171] QL: add implicit -all to a query pack to match the CodeQL pack resolution --- ql/ql/src/codeql_ql/ast/Ast.qll | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ql/ql/src/codeql_ql/ast/Ast.qll b/ql/ql/src/codeql_ql/ast/Ast.qll index 7642279dc59..a626bc2e53c 100644 --- a/ql/ql/src/codeql_ql/ast/Ast.qll +++ b/ql/ql/src/codeql_ql/ast/Ast.qll @@ -2532,8 +2532,15 @@ module YAML { * Gets a QLPack that this QLPack depends on. */ QLPack getADependency() { - exists(string name | this.hasDependency(name, _) | - result.getName().replaceAll("-", "/") = name.replaceAll("-", "/") + exists(string rawDep, string dep, string name | this.hasDependency(rawDep, _) | + dep = rawDep.replaceAll("-", "/") and + name = result.getName().replaceAll("-", "/") and + ( + name = dep + or + name.matches("codeql/%") and + name = dep + "/all" + ) ) } From 907c3db5caad2b30aa4b8d182e8f59f54472aa93 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Tue, 10 May 2022 14:27:32 +0200 Subject: [PATCH 165/171] Address comments Co-authored-by: Nick Rolfe --- ruby/ql/lib/codeql/ruby/ast/Method.qll | 2 +- .../ruby_call_method.ql | 6 ------ ruby/ql/test/library-tests/ast/TreeSitter.ql | 21 ++++++++++++++++--- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/ast/Method.qll b/ruby/ql/lib/codeql/ruby/ast/Method.qll index 8e4ea870e03..510e48a4eaf 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Method.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Method.qll @@ -253,7 +253,7 @@ class Lambda extends Callable, BodyStmt, TLambda { /** A block. */ class Block extends Callable, StmtSequence, Scope, TBlock { /** - * Get a local variable declared by this block. + * Gets a local variable declared by this block. * For example `local` in `{ | param; local| puts param }`. */ LocalVariableWriteAccess getALocalVariable() { result = this.getLocalVariable(_) } diff --git a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_method.ql b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_method.ql index 200fad69b31..bd93c22455c 100644 --- a/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_method.ql +++ b/ruby/ql/lib/upgrades/9fdd1d40fd3c3f8f9db8fabf5a353580d14c663a/ruby_call_method.ql @@ -18,12 +18,6 @@ class NormalRubyCall extends RubyCall, @ruby_call { override RubyMethod getMethod() { result = method } } -class ImplicitRubyCall extends RubyCall, @ruby_call { - ImplicitRubyCall() { ruby_call_def(this, any(@ruby_argument_list a)) } - - override RubyMethod getMethod() { none() } -} - class ScopeResolutionCall extends RubyCall, @ruby_scope_resolution { private @ruby_token_identifier method; diff --git a/ruby/ql/test/library-tests/ast/TreeSitter.ql b/ruby/ql/test/library-tests/ast/TreeSitter.ql index 19ef2794188..851ad9fe663 100644 --- a/ruby/ql/test/library-tests/ast/TreeSitter.ql +++ b/ruby/ql/test/library-tests/ast/TreeSitter.ql @@ -2,22 +2,37 @@ * @kind graph */ -import codeql.ruby.ast.internal.TreeSitter::Ruby +import codeql.ruby.ast.internal.TreeSitter +import codeql.Locations /** * Holds if `node` belongs to the output tree, and its property `key` has the * given `value`. */ -query predicate nodes(AstNode node, string key, string value) { +query predicate nodes(Ruby::AstNode node, string key, string value) { key = "semmle.label" and value = "[" + node.getPrimaryQlClasses() + "] " + node.toString() + or + key = "semmle.order" and + value = + any(int i | + node = + rank[i](Ruby::AstNode n, Location l | + l = n.getLocation() + | + n + order by + l.getFile().getRelativePath(), l.getFile().getAbsolutePath(), l.getStartLine(), + l.getStartColumn(), l.getEndLine() desc, l.getEndColumn() desc, n.toString() + ) + ).toString() } /** * Holds if `target` is a child of `source` in the AST, and property `key` of * the edge has the given `value`. */ -query predicate edges(AstNode source, AstNode target, string key, string value) { +query predicate edges(Ruby::AstNode source, Ruby::AstNode target, string key, string value) { source = target.getParent() and key = ["semmle.label", "semmle.order"] and value = target.getParentIndex().toString() From c217a1e5025776a8c04e1f8525dd9c99c6a47b7e Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 11 May 2022 11:03:13 +0200 Subject: [PATCH 166/171] Update java/ql/lib/semmle/code/java/Expr.qll --- java/ql/lib/semmle/code/java/Expr.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index 60d001054b8..ff55c5335f6 100755 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -2174,6 +2174,6 @@ class ValueDiscardingExpr extends Expr { ) ) and // Ignore if this expression is a method call with `void` as return type - not getType() instanceof VoidType + not this.getType() instanceof VoidType } } From 84ad45c665ffca545c39742e25bac9aba8084bf3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 11 May 2022 11:33:35 +0200 Subject: [PATCH 167/171] Python: Fix Django import --- python/ql/src/experimental/semmle/python/frameworks/Django.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/ql/src/experimental/semmle/python/frameworks/Django.qll b/python/ql/src/experimental/semmle/python/frameworks/Django.qll index 6e580773084..03462649792 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Django.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Django.qll @@ -151,7 +151,8 @@ private module ExperimentalPrivateDjango { */ class DjangoResponseSetCookieCall extends DataFlow::MethodCallNode, Cookie::Range { DjangoResponseSetCookieCall() { - this.calls(django::http::response::HttpResponse::instance(), "set_cookie") + this.calls(PrivateDjango::DjangoImpl::Http::Response::HttpResponse::instance(), + "set_cookie") } override DataFlow::Node getNameArg() { From a902d3d8f0cb8a1bd82b9c80f010c23e878d025e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 11 May 2022 11:34:16 +0200 Subject: [PATCH 168/171] Python: Add `security-severity` for `py/insecure-cookie` Matching the Java query https://github.com/github/codeql/blob/7d4767a4f57316429dda8813e6c744ecd4f16cb5/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql#L7 --- python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index ee22243e5c3..44db8f34194 100644 --- a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -4,6 +4,7 @@ * interception. * @kind problem * @problem.severity error + * @security-severity 5.0 * @id py/insecure-cookie * @tags security * external/cwe/cwe-614 From 27b99c51e9906add84a71265dcb74fea36a613b3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 11 May 2022 11:35:40 +0200 Subject: [PATCH 169/171] Python: Add placeholder precision for `py/insecure-cookie` --- python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index 44db8f34194..587759ec7f2 100644 --- a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -5,12 +5,13 @@ * @kind problem * @problem.severity error * @security-severity 5.0 + * @precision ??? * @id py/insecure-cookie * @tags security * external/cwe/cwe-614 */ -// determine precision above +// TODO: determine precision above import python import semmle.python.dataflow.new.DataFlow import experimental.semmle.python.Concepts From fc8633cc019fac4c77574d79ebebbd433df24fdc Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 11 May 2022 13:16:28 +0200 Subject: [PATCH 170/171] Python: Fix select for `py/cookie-injection` --- .../Security/CWE-614/CookieInjection.ql | 11 +-- .../Security/CWE-614/CookieInjection.expected | 90 +++++++++++++------ 2 files changed, 69 insertions(+), 32 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql b/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql index 8f7ef99789b..546c3d5e7a2 100644 --- a/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql +++ b/python/ql/src/experimental/Security/CWE-614/CookieInjection.ql @@ -1,7 +1,7 @@ /** * @name Construction of a cookie using user-supplied input. * @description Constructing cookies from user input may allow an attacker to perform a Cookie Poisoning attack. - * @kind problem + * @kind path-problem * @problem.severity error * @id py/cookie-injection * @tags security @@ -14,6 +14,7 @@ import semmle.python.dataflow.new.DataFlow import experimental.semmle.python.Concepts import experimental.semmle.python.CookieHeader import experimental.semmle.python.security.injection.CookieInjection +import DataFlow::PathGraph from CookieInjectionFlowConfig config, DataFlow::PathNode source, DataFlow::PathNode sink, @@ -21,7 +22,7 @@ from where config.hasFlowPath(source, sink) and if exists(sink.getNode().(CookieSink)) - then insecure = "and its " + sink.getNode().(CookieSink).getFlag() + " flag is not properly set" - else insecure = "" -select sink.getNode(), "Cookie is constructed from a", source.getNode(), "user-supplied input", - insecure + then insecure = ",and its " + sink.getNode().(CookieSink).getFlag() + " flag is not properly set." + else insecure = "." +select sink.getNode(), source, sink, "Cookie is constructed from a $@" + insecure, source.getNode(), + "user-supplied input" diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected index 879b1088002..d246f8b14d6 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected @@ -1,27 +1,63 @@ -| django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | and its httponly flag is not properly set | -| django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | and its samesite flag is not properly set | -| django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | and its secure flag is not properly set | -| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input | and its httponly flag is not properly set | -| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input | and its samesite flag is not properly set | -| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input | and its secure flag is not properly set | -| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | and its httponly flag is not properly set | -| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | and its samesite flag is not properly set | -| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | and its secure flag is not properly set | -| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input | and its httponly flag is not properly set | -| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input | and its samesite flag is not properly set | -| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input | and its secure flag is not properly set | -| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its httponly flag is not properly set | -| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its samesite flag is not properly set | -| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its secure flag is not properly set | -| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its httponly flag is not properly set | -| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its samesite flag is not properly set | -| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | and its secure flag is not properly set | -| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:49:24:55 | ControlFlowNode for request | user-supplied input | and its httponly flag is not properly set | -| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:49:24:55 | ControlFlowNode for request | user-supplied input | and its samesite flag is not properly set | -| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a | flask_bad.py:24:49:24:55 | ControlFlowNode for request | user-supplied input | and its secure flag is not properly set | -| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:37:32:43 | ControlFlowNode for request | user-supplied input | and its httponly flag is not properly set | -| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:37:32:43 | ControlFlowNode for request | user-supplied input | and its samesite flag is not properly set | -| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:37:32:43 | ControlFlowNode for request | user-supplied input | and its secure flag is not properly set | -| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:60:32:66 | ControlFlowNode for request | user-supplied input | and its httponly flag is not properly set | -| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:60:32:66 | ControlFlowNode for request | user-supplied input | and its samesite flag is not properly set | -| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a | flask_bad.py:32:60:32:66 | ControlFlowNode for request | user-supplied input | and its secure flag is not properly set | +edges +| django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | +| django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | +| flask_bad.py:24:21:24:27 | ControlFlowNode for request | flask_bad.py:24:21:24:32 | ControlFlowNode for Attribute | +| flask_bad.py:24:21:24:27 | ControlFlowNode for request | flask_bad.py:24:49:24:60 | ControlFlowNode for Attribute | +| flask_bad.py:24:21:24:32 | ControlFlowNode for Attribute | flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | +| flask_bad.py:24:49:24:55 | ControlFlowNode for request | flask_bad.py:24:49:24:60 | ControlFlowNode for Attribute | +| flask_bad.py:24:49:24:60 | ControlFlowNode for Attribute | flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | +| flask_bad.py:32:37:32:43 | ControlFlowNode for request | flask_bad.py:32:37:32:48 | ControlFlowNode for Attribute | +| flask_bad.py:32:37:32:43 | ControlFlowNode for request | flask_bad.py:32:60:32:71 | ControlFlowNode for Attribute | +| flask_bad.py:32:37:32:48 | ControlFlowNode for Attribute | flask_bad.py:32:37:32:56 | ControlFlowNode for Subscript | +| flask_bad.py:32:37:32:56 | ControlFlowNode for Subscript | flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | +| flask_bad.py:32:60:32:66 | ControlFlowNode for request | flask_bad.py:32:60:32:71 | ControlFlowNode for Attribute | +| flask_bad.py:32:60:32:71 | ControlFlowNode for Attribute | flask_bad.py:32:60:32:80 | ControlFlowNode for Subscript | +| flask_bad.py:32:60:32:80 | ControlFlowNode for Subscript | flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | +nodes +| django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | semmle.label | ControlFlowNode for Fstring | +| django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| flask_bad.py:24:21:24:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| flask_bad.py:24:21:24:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| flask_bad.py:24:49:24:55 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| flask_bad.py:24:49:24:60 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | semmle.label | ControlFlowNode for Fstring | +| flask_bad.py:32:37:32:43 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| flask_bad.py:32:37:32:48 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| flask_bad.py:32:37:32:56 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| flask_bad.py:32:60:32:66 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| flask_bad.py:32:60:32:71 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| flask_bad.py:32:60:32:80 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +subpaths +#select +| django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a $@,and its httponly flag is not properly set. | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | +| django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a $@,and its samesite flag is not properly set. | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | +| django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | Cookie is constructed from a $@,and its secure flag is not properly set. | django_bad.py:19:21:19:55 | ControlFlowNode for Attribute() | user-supplied input | +| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a $@,and its httponly flag is not properly set. | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input | +| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a $@,and its samesite flag is not properly set. | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input | +| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a $@,and its secure flag is not properly set. | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its httponly flag is not properly set. | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its samesite flag is not properly set. | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its secure flag is not properly set. | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its httponly flag is not properly set. | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its samesite flag is not properly set. | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input | +| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its secure flag is not properly set. | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input | +| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | flask_bad.py:24:21:24:27 | ControlFlowNode for request | flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its httponly flag is not properly set. | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | flask_bad.py:24:21:24:27 | ControlFlowNode for request | flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its samesite flag is not properly set. | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | flask_bad.py:24:21:24:27 | ControlFlowNode for request | flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its secure flag is not properly set. | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | flask_bad.py:24:21:24:27 | ControlFlowNode for request | flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its httponly flag is not properly set. | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | flask_bad.py:24:21:24:27 | ControlFlowNode for request | flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its samesite flag is not properly set. | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | flask_bad.py:24:21:24:27 | ControlFlowNode for request | flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its secure flag is not properly set. | flask_bad.py:24:21:24:27 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | flask_bad.py:24:49:24:55 | ControlFlowNode for request | flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its httponly flag is not properly set. | flask_bad.py:24:49:24:55 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | flask_bad.py:24:49:24:55 | ControlFlowNode for request | flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its samesite flag is not properly set. | flask_bad.py:24:49:24:55 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | flask_bad.py:24:49:24:55 | ControlFlowNode for request | flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its secure flag is not properly set. | flask_bad.py:24:49:24:55 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | flask_bad.py:32:37:32:43 | ControlFlowNode for request | flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its httponly flag is not properly set. | flask_bad.py:32:37:32:43 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | flask_bad.py:32:37:32:43 | ControlFlowNode for request | flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its samesite flag is not properly set. | flask_bad.py:32:37:32:43 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | flask_bad.py:32:37:32:43 | ControlFlowNode for request | flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its secure flag is not properly set. | flask_bad.py:32:37:32:43 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | flask_bad.py:32:60:32:66 | ControlFlowNode for request | flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its httponly flag is not properly set. | flask_bad.py:32:60:32:66 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | flask_bad.py:32:60:32:66 | ControlFlowNode for request | flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its samesite flag is not properly set. | flask_bad.py:32:60:32:66 | ControlFlowNode for request | user-supplied input | +| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | flask_bad.py:32:60:32:66 | ControlFlowNode for request | flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its secure flag is not properly set. | flask_bad.py:32:60:32:66 | ControlFlowNode for request | user-supplied input | From cff950f5f73a13d38d6bc26bca6928cfbb6856dc Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 11 May 2022 14:05:18 +0200 Subject: [PATCH 171/171] Python: Fix select of `py/insecure-cookie` --- .../Security/CWE-614/InsecureCookie.ql | 2 +- .../Security/CWE-614/InsecureCookie.expected | 60 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index 587759ec7f2..2fe2aee6f3e 100644 --- a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -27,4 +27,4 @@ where or not cookie.isSameSite() and alert = "samesite" -select cookie, "Cookie is added without the ", alert, " flag properly set." +select cookie, "Cookie is added without the '" + alert + "' flag properly set." diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected b/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected index 1ece5048db8..61f9b9b7469 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected @@ -1,30 +1,30 @@ -| django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | -| django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | -| django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | -| django_bad.py:13:5:13:26 | ControlFlowNode for Subscript | Cookie is added without the | httponly | flag properly set. | -| django_bad.py:13:5:13:26 | ControlFlowNode for Subscript | Cookie is added without the | samesite | flag properly set. | -| django_bad.py:13:5:13:26 | ControlFlowNode for Subscript | Cookie is added without the | secure | flag properly set. | -| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | -| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | -| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | -| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the | httponly | flag properly set. | -| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the | samesite | flag properly set. | -| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the | secure | flag properly set. | -| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | -| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | -| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | -| flask_bad.py:9:5:10:52 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | -| flask_bad.py:9:5:10:52 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | -| flask_bad.py:9:5:10:52 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | -| flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the | httponly | flag properly set. | -| flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the | samesite | flag properly set. | -| flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the | secure | flag properly set. | -| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | -| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | -| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | -| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the | httponly | flag properly set. | -| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the | samesite | flag properly set. | -| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the | secure | flag properly set. | -| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the | httponly | flag properly set. | -| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the | samesite | flag properly set. | -| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the | secure | flag properly set. | +| django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the 'httponly' flag properly set. | +| django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the 'samesite' flag properly set. | +| django_bad.py:6:5:7:52 | ControlFlowNode for Attribute() | Cookie is added without the 'secure' flag properly set. | +| django_bad.py:13:5:13:26 | ControlFlowNode for Subscript | Cookie is added without the 'httponly' flag properly set. | +| django_bad.py:13:5:13:26 | ControlFlowNode for Subscript | Cookie is added without the 'samesite' flag properly set. | +| django_bad.py:13:5:13:26 | ControlFlowNode for Subscript | Cookie is added without the 'secure' flag properly set. | +| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the 'httponly' flag properly set. | +| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the 'samesite' flag properly set. | +| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the 'secure' flag properly set. | +| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the 'httponly' flag properly set. | +| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the 'samesite' flag properly set. | +| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the 'secure' flag properly set. | +| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the 'httponly' flag properly set. | +| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the 'samesite' flag properly set. | +| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the 'secure' flag properly set. | +| flask_bad.py:9:5:10:52 | ControlFlowNode for Attribute() | Cookie is added without the 'httponly' flag properly set. | +| flask_bad.py:9:5:10:52 | ControlFlowNode for Attribute() | Cookie is added without the 'samesite' flag properly set. | +| flask_bad.py:9:5:10:52 | ControlFlowNode for Attribute() | Cookie is added without the 'secure' flag properly set. | +| flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the 'httponly' flag properly set. | +| flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the 'samesite' flag properly set. | +| flask_bad.py:17:5:17:30 | ControlFlowNode for Subscript | Cookie is added without the 'secure' flag properly set. | +| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the 'httponly' flag properly set. | +| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the 'samesite' flag properly set. | +| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the 'secure' flag properly set. | +| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the 'httponly' flag properly set. | +| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the 'samesite' flag properly set. | +| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the 'secure' flag properly set. | +| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the 'httponly' flag properly set. | +| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the 'samesite' flag properly set. | +| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the 'secure' flag properly set. |