From e5862a942ffbb1ab29b5b24e94a8503a3e7610f3 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 22 Apr 2021 19:59:04 +0100 Subject: [PATCH 01/66] WIP rb/overly-permissive-file query --- .../security/cwe-732/WeakFilePermissions.ql | 79 +++++++++++++++++++ .../security/cwe-732/FilePermissions.rb | 58 ++++++++++++++ .../cwe-732/WeakFilePermissions.expected | 11 +++ .../cwe-732/WeakFilePermissions.qlref | 1 + 4 files changed, 149 insertions(+) create mode 100644 ql/src/queries/security/cwe-732/WeakFilePermissions.ql create mode 100644 ql/test/query-tests/security/cwe-732/FilePermissions.rb create mode 100644 ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected create mode 100644 ql/test/query-tests/security/cwe-732/WeakFilePermissions.qlref diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql new file mode 100644 index 00000000000..aed1f9f6fa2 --- /dev/null +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -0,0 +1,79 @@ +/** + * @name Overly permissive file permissions + * @description Allowing files to be readable or writable by users other than the owner may allow sensitive information to be accessed. + * @kind problem + * @problem.severity warning + * @id rb/overly-permissive-file + * @tags external/cwe/cwe-732 + * security + * @precision low + */ + +import ruby +private import codeql_ruby.dataflow.SSA + +// TODO: account for flows through tuple assignments +// TODO: full dataflow? +/** An expression referencing the File or FileUtils module */ +class FileModuleAccess extends Expr { + FileModuleAccess() { + this.(ConstantAccess).getName() = "File" + or + this.(ConstantAccess).getName() = "FileUtils" + or + exists(FileModuleAccess fma, Ssa::WriteDefinition def | + def.getARead() = this.getAControlFlowNode() and + def.getWriteAccess().getParent().(Assignment).getRightOperand() = fma + ) + } +} + +/** An expression specifing a file permission that allows group/others read or write access */ +class PermissivePermissionsExpr extends Expr { + PermissivePermissionsExpr() { + this.(IntegerLiteral).getValueText().regexpMatch("0[0-7](([2-7].)|.[2-7])") + or + this.(IntegerLiteral) + .getValueText() + .regexpMatch("0b[01]{3}+((1[01]{5}+)|([01]1[01]{4}+)|([01]{3}+1[01]{2}+)|([01]{4}+1[01]))") + or + // TODO: non-literal expressions? underscores? decimal/hex literals? + // adding/setting read or write permissions for all/group/owner + this.(StringLiteral).getValueText().regexpMatch(".*[ago][^-=+]*[+=]*[rwxXst]*[rw].*") + or + exists(PermissivePermissionsExpr ppe, Ssa::WriteDefinition def | + def.getARead() = this.getAControlFlowNode() and + def.getWriteAccess().getParent().(Assignment).getRightOperand() = ppe + ) + } +} + +/** A call to a method of File or FileUtils that may modify file permissions */ +class PermissionSettingMethodCall extends MethodCall { + private string methodName; + private Expr permArg; + + PermissionSettingMethodCall() { + this.getReceiver() instanceof FileModuleAccess and + this.getMethodName() = methodName and + ( + methodName in ["chmod", "chmod_R", "lchmod"] and permArg = this.getArgument(0) + or + methodName = "mkfifo" and permArg = this.getArgument(1) + or + methodName in ["new", "open"] and permArg = this.getArgument(2) + or + methodName in ["install", "makedirs", "mkdir", "mkdir_p", "mkpath"] and + permArg = this.getKeywordArgument("mode") + // TODO: defaults for optional args? This may depend on the umask + ) + } + + Expr getPermissionArgument() { result = permArg } + + predicate isPermissive() { this.getPermissionArgument() instanceof PermissivePermissionsExpr } +} + +from PermissionSettingMethodCall c +where c.isPermissive() +select c, "Overly permissive mask sets file to " + c.getPermissionArgument() + "." diff --git a/ql/test/query-tests/security/cwe-732/FilePermissions.rb b/ql/test/query-tests/security/cwe-732/FilePermissions.rb new file mode 100644 index 00000000000..7edb567a8e6 --- /dev/null +++ b/ql/test/query-tests/security/cwe-732/FilePermissions.rb @@ -0,0 +1,58 @@ +require "fileutils" + +def run_chmod_1(filename) + FileUtils.chmod 0222, filename + FileUtils.chmod 0622, filename + FileUtils.chmod 0755, filename + FileUtils.chmod 0777, filename +end + +module DummyModule + def chmod(mode, list, options = {} ) + list + end +end + +def run_chmod_2(filename) + foo = FileUtils + bar = foo + baz = Dummy + # "safe" + baz.chmod 0755, filename + baz = bar + # unsafe + baz.chmod 0755, filename +end + +def run_chmod_3(filename) + # TODO: we currently miss this + foo = FileUtils + bar, baz = foo, 7 + bar.chmod 0755, filename +end + +def run_chmod_4(filename) + # safe permissions + FileUtils.chmod 0700, filename + FileUtils.chmod 0711, filename + FileUtils.chmod 0701, filename + FileUtils.chmod 0710, filename +end + +def run_chmod_5(filename) + perm = 0777 + FileUtils.chmod perm, filename + perm2 = perm + FileUtils.chmod perm2, filename + + perm = "u=wrx,g=rwx,o=x" + perm2 = perm + FileUtils.chmod perm2, filename + FileUtils.chmod "u=rwx,o+r", filename + FileUtils.chmod "u=rwx,go-r", filename + FileUtils.chmod "a+rw", filename +end + +def run_chmod_R(filename) + File.chmod_R 0755, filename +end diff --git a/ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected b/ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected new file mode 100644 index 00000000000..9ef91fc15bd --- /dev/null +++ b/ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected @@ -0,0 +1,11 @@ +| FilePermissions.rb:4:3:4:32 | call to chmod | Overly permissive mask sets file to 0222. | +| FilePermissions.rb:5:3:5:32 | call to chmod | Overly permissive mask sets file to 0622. | +| FilePermissions.rb:6:3:6:32 | call to chmod | Overly permissive mask sets file to 0755. | +| FilePermissions.rb:7:3:7:32 | call to chmod | Overly permissive mask sets file to 0777. | +| FilePermissions.rb:24:3:24:26 | call to chmod | Overly permissive mask sets file to 0755. | +| FilePermissions.rb:44:3:44:32 | call to chmod | Overly permissive mask sets file to perm. | +| FilePermissions.rb:46:3:46:33 | call to chmod | Overly permissive mask sets file to perm2. | +| FilePermissions.rb:50:3:50:33 | call to chmod | Overly permissive mask sets file to perm2. | +| FilePermissions.rb:51:3:51:39 | call to chmod | Overly permissive mask sets file to "u=rwx,o+r". | +| FilePermissions.rb:53:3:53:34 | call to chmod | Overly permissive mask sets file to "a+rw". | +| FilePermissions.rb:57:3:57:29 | call to chmod_R | Overly permissive mask sets file to 0755. | diff --git a/ql/test/query-tests/security/cwe-732/WeakFilePermissions.qlref b/ql/test/query-tests/security/cwe-732/WeakFilePermissions.qlref new file mode 100644 index 00000000000..bf19b31509d --- /dev/null +++ b/ql/test/query-tests/security/cwe-732/WeakFilePermissions.qlref @@ -0,0 +1 @@ +queries/security/cwe-732/WeakFilePermissions.ql From e3d393b7c10011a52f96374b9863f048fca7f13b Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 28 Apr 2021 15:40:58 +0100 Subject: [PATCH 02/66] use full dataflow for permission args in rb/overly-permissive-file --- .../security/cwe-732/WeakFilePermissions.ql | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql index aed1f9f6fa2..0ac0b518aa6 100644 --- a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -1,7 +1,7 @@ /** * @name Overly permissive file permissions * @description Allowing files to be readable or writable by users other than the owner may allow sensitive information to be accessed. - * @kind problem + * @kind path-problem * @problem.severity warning * @id rb/overly-permissive-file * @tags external/cwe/cwe-732 @@ -11,9 +11,10 @@ import ruby private import codeql_ruby.dataflow.SSA +private import codeql_ruby.dataflow.internal.DataFlowImpl as DataFlow // TODO: account for flows through tuple assignments -// TODO: full dataflow? + /** An expression referencing the File or FileUtils module */ class FileModuleAccess extends Expr { FileModuleAccess() { @@ -40,11 +41,6 @@ class PermissivePermissionsExpr extends Expr { // TODO: non-literal expressions? underscores? decimal/hex literals? // adding/setting read or write permissions for all/group/owner this.(StringLiteral).getValueText().regexpMatch(".*[ago][^-=+]*[+=]*[rwxXst]*[rw].*") - or - exists(PermissivePermissionsExpr ppe, Ssa::WriteDefinition def | - def.getARead() = this.getAControlFlowNode() and - def.getWriteAccess().getParent().(Assignment).getRightOperand() = ppe - ) } } @@ -70,10 +66,21 @@ class PermissionSettingMethodCall extends MethodCall { } Expr getPermissionArgument() { result = permArg } - - predicate isPermissive() { this.getPermissionArgument() instanceof PermissivePermissionsExpr } } -from PermissionSettingMethodCall c -where c.isPermissive() -select c, "Overly permissive mask sets file to " + c.getPermissionArgument() + "." +class PermissivePermissionsConfig extends DataFlow::Configuration { + PermissivePermissionsConfig() { this = "PermissivePermissionsConfig" } + + override predicate isSource(DataFlow::Node source) { + exists(PermissivePermissionsExpr ppe | source.asExpr().getExpr() = ppe) + } + + override predicate isSink(DataFlow::Node sink) { + exists(PermissionSettingMethodCall c | sink.asExpr().getExpr() = c.getPermissionArgument()) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, PermissivePermissionsConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Overly permissive mask sets file to $@.", + source.getNode(), source.getNode().toString() \ No newline at end of file From 7a72d8ec2f39f6a72512a0cf5106b8b9e195da4b Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 28 Apr 2021 15:51:08 +0100 Subject: [PATCH 03/66] add qhelp for rb/overly-permissive-file --- .../cwe-732/WeakFilePermissions.qhelp | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 ql/src/queries/security/cwe-732/WeakFilePermissions.qhelp diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.qhelp b/ql/src/queries/security/cwe-732/WeakFilePermissions.qhelp new file mode 100644 index 00000000000..a5f8997e911 --- /dev/null +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.qhelp @@ -0,0 +1,26 @@ + + + + +

+When creating a file, POSIX systems allow permissions to be specified +for owner, group and others separately. Permissions should be kept as +strict as possible, preventing access to the files contents by other users. +

+ +
+ + +

+Restrict the file permissions of files to prevent any but the owner being able to read or write to that file +

+
+ + +
  • +Wikipedia: +File system permissions. +
  • +
    + +
    From 0a6dc6f15003cda44eb15eb5588be10c33c5244d Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 28 Apr 2021 16:31:07 +0100 Subject: [PATCH 04/66] update WeakFilePermissions.expected --- .../cwe-732/WeakFilePermissions.expected | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected b/ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected index 9ef91fc15bd..1b5d49b2d28 100644 --- a/ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected +++ b/ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected @@ -1,11 +1,11 @@ -| FilePermissions.rb:4:3:4:32 | call to chmod | Overly permissive mask sets file to 0222. | -| FilePermissions.rb:5:3:5:32 | call to chmod | Overly permissive mask sets file to 0622. | -| FilePermissions.rb:6:3:6:32 | call to chmod | Overly permissive mask sets file to 0755. | -| FilePermissions.rb:7:3:7:32 | call to chmod | Overly permissive mask sets file to 0777. | -| FilePermissions.rb:24:3:24:26 | call to chmod | Overly permissive mask sets file to 0755. | -| FilePermissions.rb:44:3:44:32 | call to chmod | Overly permissive mask sets file to perm. | -| FilePermissions.rb:46:3:46:33 | call to chmod | Overly permissive mask sets file to perm2. | -| FilePermissions.rb:50:3:50:33 | call to chmod | Overly permissive mask sets file to perm2. | -| FilePermissions.rb:51:3:51:39 | call to chmod | Overly permissive mask sets file to "u=rwx,o+r". | -| FilePermissions.rb:53:3:53:34 | call to chmod | Overly permissive mask sets file to "a+rw". | -| FilePermissions.rb:57:3:57:29 | call to chmod_R | Overly permissive mask sets file to 0755. | +| FilePermissions.rb:4:19:4:22 | 0222 | FilePermissions.rb:4:19:4:22 | 0222 | FilePermissions.rb:4:19:4:22 | 0222 | Overly permissive mask sets file to $@. | FilePermissions.rb:4:19:4:22 | 0222 | 0222 | +| FilePermissions.rb:5:19:5:22 | 0622 | FilePermissions.rb:5:19:5:22 | 0622 | FilePermissions.rb:5:19:5:22 | 0622 | Overly permissive mask sets file to $@. | FilePermissions.rb:5:19:5:22 | 0622 | 0622 | +| FilePermissions.rb:6:19:6:22 | 0755 | FilePermissions.rb:6:19:6:22 | 0755 | FilePermissions.rb:6:19:6:22 | 0755 | Overly permissive mask sets file to $@. | FilePermissions.rb:6:19:6:22 | 0755 | 0755 | +| FilePermissions.rb:7:19:7:22 | 0777 | FilePermissions.rb:7:19:7:22 | 0777 | FilePermissions.rb:7:19:7:22 | 0777 | Overly permissive mask sets file to $@. | FilePermissions.rb:7:19:7:22 | 0777 | 0777 | +| FilePermissions.rb:24:13:24:16 | 0755 | FilePermissions.rb:24:13:24:16 | 0755 | FilePermissions.rb:24:13:24:16 | 0755 | Overly permissive mask sets file to $@. | FilePermissions.rb:24:13:24:16 | 0755 | 0755 | +| FilePermissions.rb:44:19:44:22 | perm | FilePermissions.rb:43:10:43:13 | 0777 : | FilePermissions.rb:44:19:44:22 | perm | Overly permissive mask sets file to $@. | FilePermissions.rb:43:10:43:13 | 0777 | 0777 | +| FilePermissions.rb:46:19:46:23 | perm2 | FilePermissions.rb:43:10:43:13 | 0777 : | FilePermissions.rb:46:19:46:23 | perm2 | Overly permissive mask sets file to $@. | FilePermissions.rb:43:10:43:13 | 0777 | 0777 | +| FilePermissions.rb:50:19:50:23 | perm2 | FilePermissions.rb:48:10:48:26 | "u=wrx,g=rwx,o=x" : | FilePermissions.rb:50:19:50:23 | perm2 | Overly permissive mask sets file to $@. | FilePermissions.rb:48:10:48:26 | "u=wrx,g=rwx,o=x" | "u=wrx,g=rwx,o=x" | +| FilePermissions.rb:51:19:51:29 | "u=rwx,o+r" | FilePermissions.rb:51:19:51:29 | "u=rwx,o+r" | FilePermissions.rb:51:19:51:29 | "u=rwx,o+r" | Overly permissive mask sets file to $@. | FilePermissions.rb:51:19:51:29 | "u=rwx,o+r" | "u=rwx,o+r" | +| FilePermissions.rb:53:19:53:24 | "a+rw" | FilePermissions.rb:53:19:53:24 | "a+rw" | FilePermissions.rb:53:19:53:24 | "a+rw" | Overly permissive mask sets file to $@. | FilePermissions.rb:53:19:53:24 | "a+rw" | "a+rw" | +| FilePermissions.rb:57:16:57:19 | 0755 | FilePermissions.rb:57:16:57:19 | 0755 | FilePermissions.rb:57:16:57:19 | 0755 | Overly permissive mask sets file to $@. | FilePermissions.rb:57:16:57:19 | 0755 | 0755 | From c1c437f0206ec7bcbbca2cc807a2aa149df883de Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Fri, 16 Apr 2021 16:54:30 +0100 Subject: [PATCH 05/66] Minimal implementation of shared type-tracking library --- .../dataflow/internal/DataFlowDispatch.qll | 6 + .../dataflow/internal/DataFlowPublic.qll | 32 ++ .../codeql_ruby/typetracking/TypeTracker.qll | 420 ++++++++++++++++++ .../typetracking/TypeTrackerPrivate.qll | 119 +++++ 4 files changed, 577 insertions(+) create mode 100644 ql/src/codeql_ruby/typetracking/TypeTracker.qll create mode 100644 ql/src/codeql_ruby/typetracking/TypeTrackerPrivate.qll diff --git a/ql/src/codeql_ruby/dataflow/internal/DataFlowDispatch.qll b/ql/src/codeql_ruby/dataflow/internal/DataFlowDispatch.qll index b412793ffaa..a539e18b069 100644 --- a/ql/src/codeql_ruby/dataflow/internal/DataFlowDispatch.qll +++ b/ql/src/codeql_ruby/dataflow/internal/DataFlowDispatch.qll @@ -40,6 +40,12 @@ class DataFlowCallable = CfgScope; class DataFlowCall extends CfgNodes::ExprNodes::CallCfgNode { DataFlowCallable getEnclosingCallable() { result = this.getScope() } + + DataFlowCallable getCallable() { + // TODO: this is a placeholder that finds a method with the same name, iff it's uniquely named. + result = + unique(DataFlowCallable c | c.(Method).getName() = this.getNode().(MethodCall).getMethodName()) + } } /** Gets a viable run-time target for the call `call`. */ diff --git a/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll b/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll index 7a8d40a5e1a..0a8716a0b07 100644 --- a/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll +++ b/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll @@ -2,6 +2,7 @@ private import ruby private import DataFlowDispatch private import DataFlowPrivate private import codeql_ruby.CFG +private import codeql_ruby.typetracking.TypeTracker /** * An element, viewed as a node in a data flow graph. Either an expression @@ -36,6 +37,14 @@ class Node extends TNode { ) { getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } + + /** + * Gets a node that this node may flow to using one heap and/or interprocedural step. + * + * See `TypeTracker` for more details about how to use this. + */ + pragma[inline] + Node track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) } } /** @@ -73,6 +82,29 @@ class ParameterNode extends Node, TParameterNode { predicate isParameterOf(Callable c, int i) { p = c.getParameter(i) } } +/** + * A data-flow node that is a source of local flow. + */ +class LocalSourceNode extends Node { + LocalSourceNode() { not simpleLocalFlowStep+(any(ExprNode n), this) } + + /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ + pragma[inline] + predicate flowsTo(Node nodeTo) { hasLocalSource(nodeTo, this) } +} + +predicate hasLocalSource(Node sink, Node source) { + // Declaring `source` to be a `SourceNode` currently causes a redundant check in the + // recursive case, so instead we check it explicitly here. + source = sink and + source instanceof LocalSourceNode + or + exists(Node mid | + hasLocalSource(mid, source) and + simpleLocalFlowStep(mid, sink) + ) +} + /** Gets a node corresponding to expression `e`. */ ExprNode exprNode(CfgNodes::ExprCfgNode e) { result.getExprNode() = e } diff --git a/ql/src/codeql_ruby/typetracking/TypeTracker.qll b/ql/src/codeql_ruby/typetracking/TypeTracker.qll new file mode 100644 index 00000000000..46461d3e22e --- /dev/null +++ b/ql/src/codeql_ruby/typetracking/TypeTracker.qll @@ -0,0 +1,420 @@ +/** Step Summaries and Type Tracking */ + +private import TypeTrackerPrivate + +/** + * Any string that may appear as the name of a piece of content. This will usually include things like: + * - Attribute names (in Python) + * - Property names (in JavaScript) + * + * In general, this can also be used to model things like stores to specific list indices. To ensure + * correctness, it is important that + * + * - different types of content do not have overlapping names, and + * - the empty string `""` is not a valid piece of content, as it is used to indicate the absence of + * content instead. + */ +class ContentName extends string { + ContentName() { this = getPossibleContentName() } +} + +/** Either a content name, or the empty string (representing no content). */ +class OptionalContentName extends string { + OptionalContentName() { this instanceof ContentName or this = "" } +} + +/** + * A description of a step on an inter-procedural data flow path. + */ +private newtype TStepSummary = + LevelStep() or + CallStep() or + ReturnStep() or + StoreStep(ContentName content) or + LoadStep(ContentName content) + +/** + * INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead. + * + * A description of a step on an inter-procedural data flow path. + */ +class StepSummary extends TStepSummary { + /** Gets a textual representation of this step summary. */ + string toString() { + this instanceof LevelStep and result = "level" + or + this instanceof CallStep and result = "call" + or + this instanceof ReturnStep and result = "return" + or + exists(string content | this = StoreStep(content) | result = "store " + content) + or + exists(string content | this = LoadStep(content) | result = "load " + content) + } +} + +/** Provides predicates for updating step summaries (`StepSummary`s). */ +module StepSummary { + /** + * Gets the summary that corresponds to having taken a forwards + * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. + */ + cached + predicate step(LocalSourceNode nodeFrom, LocalSourceNode nodeTo, StepSummary summary) { + exists(Node mid | nodeFrom.flowsTo(mid) and smallstep(mid, nodeTo, summary)) + } + + /** + * Gets the summary that corresponds to having taken a forwards + * local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. + * + * Unlike `StepSummary::step`, this predicate does not compress + * type-preserving steps. + */ + predicate smallstep(Node nodeFrom, Node nodeTo, StepSummary summary) { + typePreservingStep(nodeFrom, nodeTo) and + summary = LevelStep() + or + callStep(nodeFrom, nodeTo) and summary = CallStep() + or + returnStep(nodeFrom, nodeTo) and + summary = ReturnStep() + or + exists(string content | + localSourceStoreStep(nodeFrom, nodeTo, content) and + summary = StoreStep(content) + or + basicLoadStep(nodeFrom, nodeTo, content) and summary = LoadStep(content) + ) + } + + /** + * Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`. + * + * Note that `nodeTo` will always be a local source node that flows to the place where the content + * is written in `basicStoreStep`. This may lead to the flow of information going "back in time" + * from the point of view of the execution of the program. + * + * For instance, if we interpret attribute writes in Python as writing to content with the same + * name as the attribute and consider the following snippet + * + * ```python + * def foo(y): + * x = Foo() + * bar(x) + * x.attr = y + * baz(x) + * + * def bar(x): + * z = x.attr + * ``` + * for the attribute write `x.attr = y`, we will have `content` being the literal string `"attr"`, + * `nodeFrom` will be `y`, and `nodeTo` will be the object `Foo()` created on the first line of the + * function. This means we will track the fact that `x.attr` can have the type of `y` into the + * assignment to `z` inside `bar`, even though this attribute write happens _after_ `bar` is called. + */ + predicate localSourceStoreStep(Node nodeFrom, LocalSourceNode nodeTo, string content) { + exists(Node obj | nodeTo.flowsTo(obj) and basicStoreStep(nodeFrom, obj, content)) + } +} + +private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalContentName content) + +/** + * Summary of the steps needed to track a value to a given dataflow node. + * + * This can be used to track objects that implement a certain API in order to + * recognize calls to that API. Note that type-tracking does not by itself provide a + * source/sink relation, that is, it may determine that a node has a given type, + * but it won't determine where that type came from. + * + * It is recommended that all uses of this type are written in the following form, + * for tracking some type `myType`: + * ```ql + * DataFlow::LocalSourceNode myType(DataFlow::TypeTracker t) { + * t.start() and + * result = < source of myType > + * or + * exists (DataFlow::TypeTracker t2 | + * result = myType(t2).track(t2, t) + * ) + * } + * + * DataFlow::Node myType() { myType(DataFlow::TypeTracker::end()).flowsTo(result) } + * ``` + * + * Instead of `result = myType(t2).track(t2, t)`, you can also use the equivalent + * `t = t2.step(myType(t2), result)`. If you additionally want to track individual + * intra-procedural steps, use `t = t2.smallstep(myCallback(t2), result)`. + */ +class TypeTracker extends TTypeTracker { + Boolean hasCall; + OptionalContentName content; + + TypeTracker() { this = MkTypeTracker(hasCall, content) } + + /** Gets the summary resulting from appending `step` to this type-tracking summary. */ + cached + TypeTracker append(StepSummary step) { + step = LevelStep() and result = this + or + step = CallStep() and result = MkTypeTracker(true, content) + or + step = ReturnStep() and hasCall = false and result = this + or + step = LoadStep(content) and result = MkTypeTracker(hasCall, "") + or + exists(string p | step = StoreStep(p) and content = "" and result = MkTypeTracker(hasCall, p)) + } + + /** Gets a textual representation of this summary. */ + string toString() { + exists(string withCall, string withContent | + (if hasCall = true then withCall = "with" else withCall = "without") and + (if content != "" then withContent = " with content " + content else withContent = "") and + result = "type tracker " + withCall + " call steps" + withContent + ) + } + + /** + * Holds if this is the starting point of type tracking. + */ + predicate start() { hasCall = false and content = "" } + + /** + * Holds if this is the starting point of type tracking, and the value starts in the content named `contentName`. + * The type tracking only ends after the content has been loaded. + */ + predicate startInContent(ContentName contentName) { hasCall = false and content = contentName } + + /** + * Holds if this is the starting point of type tracking + * when tracking a parameter into a call, but not out of it. + */ + predicate call() { hasCall = true and content = "" } + + /** + * Holds if this is the end point of type tracking. + */ + predicate end() { content = "" } + + /** + * INTERNAL. DO NOT USE. + * + * Holds if this type has been tracked into a call. + */ + boolean hasCall() { result = hasCall } + + /** + * INTERNAL. DO NOT USE. + * + * Gets the content associated with this type tracker. + */ + string getContent() { result = content } + + /** + * Gets a type tracker that starts where this one has left off to allow continued + * tracking. + * + * This predicate is only defined if the type is not associated to a piece of content. + */ + TypeTracker continue() { content = "" and result = this } + + /** + * Gets the summary that corresponds to having taken a forwards + * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. + */ + pragma[inline] + TypeTracker step(LocalSourceNode nodeFrom, Node nodeTo) { + exists(StepSummary summary | + StepSummary::step(nodeFrom, nodeTo, summary) and + result = this.append(summary) + ) + } + + /** + * Gets the summary that corresponds to having taken a forwards + * local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. + * + * Unlike `TypeTracker::step`, this predicate exposes all edges + * in the flow graph, and not just the edges between `Node`s. + * It may therefore be less performant. + * + * Type tracking predicates using small steps typically take the following form: + * ```ql + * DataFlow::Node myType(DataFlow::TypeTracker t) { + * t.start() and + * result = < source of myType > + * or + * exists (DataFlow::TypeTracker t2 | + * t = t2.smallstep(myType(t2), result) + * ) + * } + * + * DataFlow::Node myType() { + * result = myType(DataFlow::TypeTracker::end()) + * } + * ``` + */ + pragma[inline] + TypeTracker smallstep(Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + StepSummary::smallstep(nodeFrom, nodeTo, summary) and + result = this.append(summary) + ) + or + typePreservingStep(nodeFrom, nodeTo) and + result = this + } +} + +/** Provides predicates for implementing custom `TypeTracker`s. */ +module TypeTracker { + /** + * Gets a valid end point of type tracking. + */ + TypeTracker end() { result.end() } +} + +private newtype TTypeBackTracker = MkTypeBackTracker(Boolean hasReturn, OptionalContentName content) + +/** + * Summary of the steps needed to back-track a use of a value to a given dataflow node. + * + * This can for example be used to track callbacks that are passed to a certain API, + * so we can model specific parameters of that callback as having a certain type. + * + * Note that type back-tracking does not provide a source/sink relation, that is, + * it may determine that a node will be used in an API call somewhere, but it won't + * determine exactly where that use was, or the path that led to the use. + * + * It is recommended that all uses of this type are written in the following form, + * for back-tracking some callback type `myCallback`: + * + * ```ql + * DataFlow::LocalSourceNode myCallback(DataFlow::TypeBackTracker t) { + * t.start() and + * result = (< some API call >).getArgument(< n >).getALocalSource() + * or + * exists (DataFlow::TypeBackTracker t2 | + * result = myCallback(t2).backtrack(t2, t) + * ) + * } + * + * DataFlow::LocalSourceNode myCallback() { result = myCallback(DataFlow::TypeBackTracker::end()) } + * ``` + * + * Instead of `result = myCallback(t2).backtrack(t2, t)`, you can also use the equivalent + * `t2 = t.step(result, myCallback(t2))`. If you additionally want to track individual + * intra-procedural steps, use `t2 = t.smallstep(result, myCallback(t2))`. + */ +class TypeBackTracker extends TTypeBackTracker { + Boolean hasReturn; + string content; + + TypeBackTracker() { this = MkTypeBackTracker(hasReturn, content) } + + /** Gets the summary resulting from prepending `step` to this type-tracking summary. */ + TypeBackTracker prepend(StepSummary step) { + step = LevelStep() and result = this + or + step = CallStep() and hasReturn = false and result = this + or + step = ReturnStep() and result = MkTypeBackTracker(true, content) + or + exists(string p | + step = LoadStep(p) and content = "" and result = MkTypeBackTracker(hasReturn, p) + ) + or + step = StoreStep(content) and result = MkTypeBackTracker(hasReturn, "") + } + + /** Gets a textual representation of this summary. */ + string toString() { + exists(string withReturn, string withContent | + (if hasReturn = true then withReturn = "with" else withReturn = "without") and + (if content != "" then withContent = " with content " + content else withContent = "") and + result = "type back-tracker " + withReturn + " return steps" + withContent + ) + } + + /** + * Holds if this is the starting point of type tracking. + */ + predicate start() { hasReturn = false and content = "" } + + /** + * Holds if this is the end point of type tracking. + */ + predicate end() { content = "" } + + /** + * INTERNAL. DO NOT USE. + * + * Holds if this type has been back-tracked into a call through return edge. + */ + boolean hasReturn() { result = hasReturn } + + /** + * Gets a type tracker that starts where this one has left off to allow continued + * tracking. + * + * This predicate is only defined if the type has not been tracked into a piece of content. + */ + TypeBackTracker continue() { content = "" and result = this } + + /** + * Gets the summary that corresponds to having taken a backwards + * heap and/or inter-procedural step from `nodeTo` to `nodeFrom`. + */ + pragma[inline] + TypeBackTracker step(LocalSourceNode nodeFrom, LocalSourceNode nodeTo) { + exists(StepSummary summary | + StepSummary::step(nodeFrom, nodeTo, summary) and + this = result.prepend(summary) + ) + } + + /** + * Gets the summary that corresponds to having taken a backwards + * local, heap and/or inter-procedural step from `nodeTo` to `nodeFrom`. + * + * Unlike `TypeBackTracker::step`, this predicate exposes all edges + * in the flowgraph, and not just the edges between + * `LocalSourceNode`s. It may therefore be less performant. + * + * Type tracking predicates using small steps typically take the following form: + * ```ql + * DataFlow::Node myType(DataFlow::TypeBackTracker t) { + * t.start() and + * result = < some API call >.getArgument(< n >) + * or + * exists (DataFlow::TypeBackTracker t2 | + * t = t2.smallstep(result, myType(t2)) + * ) + * } + * + * DataFlow::Node myType() { + * result = myType(DataFlow::TypeBackTracker::end()) + * } + * ``` + */ + pragma[inline] + TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + StepSummary::smallstep(nodeFrom, nodeTo, summary) and + this = result.prepend(summary) + ) + or + typePreservingStep(nodeFrom, nodeTo) and + this = result + } +} + +/** Provides predicates for implementing custom `TypeBackTracker`s. */ +module TypeBackTracker { + /** + * Gets a valid end point of type back-tracking. + */ + TypeBackTracker end() { result.end() } +} diff --git a/ql/src/codeql_ruby/typetracking/TypeTrackerPrivate.qll b/ql/src/codeql_ruby/typetracking/TypeTrackerPrivate.qll new file mode 100644 index 00000000000..447c60ffa93 --- /dev/null +++ b/ql/src/codeql_ruby/typetracking/TypeTrackerPrivate.qll @@ -0,0 +1,119 @@ +private import codeql_ruby.AST as AST +private import codeql_ruby.dataflow.internal.DataFlowPublic as DataFlowPublic +private import codeql_ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate +private import codeql_ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch + +class Node = DataFlowPublic::Node; + +class LocalSourceNode = DataFlowPublic::LocalSourceNode; + +/** Holds if it's reasonable to expect the data flow step from `nodeFrom` to `nodeTo` to preserve types. */ +predicate typePreservingStep(Node nodeFrom, Node nodeTo) { + DataFlowPrivate::simpleLocalFlowStep(nodeFrom, nodeTo) or + DataFlowPrivate::jumpStep(nodeFrom, nodeTo) +} + +/** + * Gets the name of a possible piece of content. This will usually include things like + * + * - Attribute names (in Python) + * - Property names (in JavaScript) + */ +string getPossibleContentName() { result = getSetterCallAttributeName(_) } + +/** Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call. */ +predicate callStep( + DataFlowPrivate::ArgumentNode nodeFrom, DataFlowPrivate::ExplicitParameterNode nodeTo +) { + exists(DataFlowDispatch::DataFlowCall call, DataFlowDispatch::DataFlowCallable callable, int i | + call.getCallable() = callable and + nodeFrom.argumentOf(call, i) and + nodeTo.isParameterOf(callable, i) + ) +} + +/** Holds if `nodeFrom` steps to `nodeTo` by being returned from a call. */ +predicate returnStep(DataFlowPrivate::ReturnNode nodeFrom, Node nodeTo) { + exists(DataFlowDispatch::DataFlowCall call | + nodeFrom.getEnclosingCallable() = call.getCallable() and + nodeTo.asExpr().getNode() = call.getNode() + ) +} + +/** + * Holds if `nodeFrom` is being written to the `content` content of the object + * in `nodeTo`. + * + * Note that the choice of `nodeTo` does not have to make sense + * "chronologically". All we care about is whether the `content` content of + * `nodeTo` can have a specific type, and the assumption is that if a specific + * type appears here, then any access of that particular content can yield + * something of that particular type. + * + * Thus, in an example such as + * + * ```rb + * def foo(y) + * x = Foo.new + * bar(x) + * x.content = y + * baz(x) + * end + * + * def bar(x) + * z = x.content + * end + * ``` + * for the content write `x.content = y`, we will have `content` being the + * literal string `"content"`, `nodeFrom` will be `y`, and `nodeTo` will be the + * `Foo` object created on the first line of the function. This means we will + * track the fact that `x.content` can have the type of `y` into the assignment + * to `z` inside `bar`, even though this content write happens _after_ `bar` is + * called. + */ +predicate basicStoreStep(Node nodeFrom, LocalSourceNode nodeTo, string content) { + // TODO: support SetterMethodCall inside TuplePattern + exists(AST::Assignment assignment, AST::SetterMethodCall call, DataFlowPublic::ExprNode receiver | + assignment.getLeftOperand() = call and + content = getSetterCallAttributeName(call) and + receiver.getExprNode().getNode() = call.getReceiver() and + assignment.getRightOperand() = nodeFrom.(DataFlowPublic::ExprNode).getExprNode().getNode() and + nodeTo.flowsTo(receiver) + ) +} + +/** + * Returns the name of the attribute being set by the setter method call, i.e. + * the name of the setter method without the trailing `=`. In the following + * example, the result is `"bar"`. + * + * ```rb + * foo.bar = 1 + * ``` + */ +private string getSetterCallAttributeName(AST::SetterMethodCall call) { + // TODO: this should be exposed in `SetterMethodCall` + not call instanceof AST::ElementReference and + exists(string setterName | + setterName = call.getMethodName() and result = setterName.prefix(setterName.length() - 1) + ) +} + +/** + * Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`. + */ +predicate basicLoadStep(Node nodeFrom, Node nodeTo, string content) { + exists(AST::MethodCall call | + call.getNumberOfArguments() = 0 and + content = call.getMethodName() and + nodeFrom.asExpr().getNode() = call.getReceiver() and + nodeTo.asExpr().getNode() = call + ) +} + +/** + * A utility class that is equivalent to `boolean` but does not require type joining. + */ +class Boolean extends boolean { + Boolean() { this = true or this = false } +} From 96ddd55191e2cc9e65732558684b0fc23e7712af Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Mon, 19 Apr 2021 12:23:10 +0100 Subject: [PATCH 06/66] Apply suggestions from code review Co-authored-by: Arthur Baars --- ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll | 2 +- ql/src/codeql_ruby/typetracking/TypeTracker.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll b/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll index 0a8716a0b07..0d957f7dd35 100644 --- a/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll +++ b/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll @@ -44,7 +44,7 @@ class Node extends TNode { * See `TypeTracker` for more details about how to use this. */ pragma[inline] - Node track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) } + LocalSourceNode track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) } } /** diff --git a/ql/src/codeql_ruby/typetracking/TypeTracker.qll b/ql/src/codeql_ruby/typetracking/TypeTracker.qll index 46461d3e22e..f8fd34723db 100644 --- a/ql/src/codeql_ruby/typetracking/TypeTracker.qll +++ b/ql/src/codeql_ruby/typetracking/TypeTracker.qll @@ -225,7 +225,7 @@ class TypeTracker extends TTypeTracker { * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. */ pragma[inline] - TypeTracker step(LocalSourceNode nodeFrom, Node nodeTo) { + TypeTracker step(LocalSourceNode nodeFrom, LocalSourceNode nodeTo) { exists(StepSummary summary | StepSummary::step(nodeFrom, nodeTo, summary) and result = this.append(summary) From f07c58ee0700bb1347544279aed6aa5bb96066c9 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Thu, 29 Apr 2021 12:13:11 +0200 Subject: [PATCH 07/66] Update codeql submodule --- codeql | 2 +- .../dataflow/internal/DataFlowImpl.qll | 9 +- .../dataflow/internal/SsaImplCommon.qll | 83 ++++++++++++------- 3 files changed, 55 insertions(+), 39 deletions(-) diff --git a/codeql b/codeql index a1ccbcdaf11..6693c5bdd0b 160000 --- a/codeql +++ b/codeql @@ -1 +1 @@ -Subproject commit a1ccbcdaf11c94fef1a99ca2dd3c23eca0acf36a +Subproject commit 6693c5bdd0b7452f9da5abda3aba9b0123b25c89 diff --git a/ql/src/codeql_ruby/dataflow/internal/DataFlowImpl.qll b/ql/src/codeql_ruby/dataflow/internal/DataFlowImpl.qll index 8b446d28b86..9498e51e7e6 100644 --- a/ql/src/codeql_ruby/dataflow/internal/DataFlowImpl.qll +++ b/ql/src/codeql_ruby/dataflow/internal/DataFlowImpl.qll @@ -2133,11 +2133,8 @@ private module Stage4 { bindingset[node, cc, config] private LocalCc getLocalCc(Node node, Cc cc, Configuration config) { - exists(Cc cc0 | - cc = pragma[only_bind_into](cc0) and - localFlowEntry(node, config) and - result = getLocalCallContext(cc0, getNodeEnclosingCallable(node)) - ) + localFlowEntry(node, config) and + result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node)) } private predicate localStep( @@ -3132,7 +3129,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt conf = mid.getConfiguration() and cc = mid.getCallContext() and sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and + localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and diff --git a/ql/src/codeql_ruby/dataflow/internal/SsaImplCommon.qll b/ql/src/codeql_ruby/dataflow/internal/SsaImplCommon.qll index be01c05b8fa..f37a4f2d074 100644 --- a/ql/src/codeql_ruby/dataflow/internal/SsaImplCommon.qll +++ b/ql/src/codeql_ruby/dataflow/internal/SsaImplCommon.qll @@ -1,5 +1,5 @@ /** - * Provides a language-independant implementation of static single assignment + * Provides a language-independent implementation of static single assignment * (SSA) form. */ @@ -316,15 +316,23 @@ private module SsaDefReaches { ) } + /** + * Holds if the reference to `def` at index `i` in basic block `bb` is the + * last reference to `v` inside `bb`. + */ + pragma[noinline] + predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) { + ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) + } + predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) { exists(ssaDefRank(def, v, bb, _, _)) } pragma[noinline] - private BasicBlock getAMaybeLiveSuccessor(Definition def, BasicBlock bb) { - result = getABasicBlockSuccessor(bb) and - not defOccursInBlock(_, bb, def.getSourceVariable()) and - ssaDefReachesEndOfBlock(bb, def, _) + private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { + ssaDefReachesEndOfBlock(bb, def, _) and + not defOccursInBlock(_, bb, def.getSourceVariable()) } /** @@ -337,7 +345,11 @@ private module SsaDefReaches { defOccursInBlock(def, bb1, _) and bb2 = getABasicBlockSuccessor(bb1) or - exists(BasicBlock mid | varBlockReaches(def, bb1, mid) | bb2 = getAMaybeLiveSuccessor(def, mid)) + exists(BasicBlock mid | + varBlockReaches(def, bb1, mid) and + ssaDefReachesThroughBlock(def, mid) and + bb2 = getABasicBlockSuccessor(mid) + ) } /** @@ -348,24 +360,16 @@ private module SsaDefReaches { */ predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { varBlockReaches(def, bb1, bb2) and - ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 and - variableRead(bb2, i2, _, _) + ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 } } private import SsaDefReaches -pragma[noinline] -private predicate ssaDefReachesEndOfBlockRec(BasicBlock bb, Definition def, SourceVariable v) { - exists(BasicBlock idom | ssaDefReachesEndOfBlock(idom, def, v) | - // The construction of SSA form ensures that each read of a variable is - // dominated by its definition. An SSA definition therefore reaches a - // control flow node if it is the _closest_ SSA definition that dominates - // the node. If two definitions dominate a node then one must dominate the - // other, so therefore the definition of _closest_ is given by the dominator - // tree. Thus, reaching definitions can be calculated in terms of dominance. - idom = getImmediateBasicBlockDominator(bb) - ) +pragma[nomagic] +predicate liveThrough(BasicBlock bb, SourceVariable v) { + liveAtExit(bb, v) and + not ssaRef(bb, _, v, SsaDef()) } /** @@ -382,9 +386,14 @@ predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable liveAtExit(bb, v) ) or - ssaDefReachesEndOfBlockRec(bb, def, v) and - liveAtExit(bb, v) and - not ssaRef(bb, _, v, SsaDef()) + // The construction of SSA form ensures that each read of a variable is + // dominated by its definition. An SSA definition therefore reaches a + // control flow node if it is the _closest_ SSA definition that dominates + // the node. If two definitions dominate a node then one must dominate the + // other, so therefore the definition of _closest_ is given by the dominator + // tree. Thus, reaching definitions can be calculated in terms of dominance. + ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and + liveThrough(bb, pragma[only_bind_into](v)) } /** @@ -433,15 +442,22 @@ predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2 bb2 = bb1 ) or - exists(SourceVariable v | ssaDefRank(def, v, bb1, i1, _) = maxSsaRefRank(bb1, v)) and + lastSsaRef(def, _, bb1, i1) and defAdjacentRead(def, bb1, bb2, i2) } +pragma[noinline] +private predicate adjacentDefRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v +) { + adjacentDefRead(def, bb1, i1, bb2, i2) and + v = def.getSourceVariable() +} + private predicate adjacentDefReachesRead( Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 ) { - adjacentDefRead(def, bb1, i1, bb2, i2) and - exists(SourceVariable v | v = def.getSourceVariable() | + exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) | ssaRef(bb1, i1, v, SsaDef()) or variableRead(bb1, i1, v, true) @@ -474,17 +490,19 @@ predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, Ba */ pragma[nomagic] predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { - exists(int rnk, SourceVariable v, int j | rnk = ssaDefRank(def, v, bb, i, _) | + exists(SourceVariable v | // Next reference to `v` inside `bb` is a write - next.definesAt(v, bb, j) and - rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) + exists(int rnk, int j | + rnk = ssaDefRank(def, v, bb, i, _) and + next.definesAt(v, bb, j) and + rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) + ) or // Can reach a write using one or more steps - rnk = maxSsaRefRank(bb, v) and + lastSsaRef(def, v, bb, i) and exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) and - next.definesAt(v, bb2, j) and - 1 = ssaRefRank(bb2, j, v, SsaDef()) + 1 = ssaDefRank(next, v, bb2, _, SsaDef()) ) ) } @@ -538,7 +556,8 @@ pragma[nomagic] predicate lastRef(Definition def, BasicBlock bb, int i) { lastRefRedef(def, bb, i, _) or - exists(SourceVariable v | ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) | + lastSsaRef(def, _, bb, i) and + ( // Can reach exit directly bb instanceof ExitBasicBlock or From 300a54384fdd798ba28b348d5c6a21a3669c24f5 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Thu, 29 Apr 2021 12:14:19 +0200 Subject: [PATCH 08/66] Add TypeTracker to identical-files.json --- .../codeql_ruby/typetracking/TypeTracker.qll | 18 +++++++++--------- ...ckerPrivate.qll => TypeTrackerSpecific.qll} | 8 +++----- scripts/identical-files.json | 6 +++++- 3 files changed, 17 insertions(+), 15 deletions(-) rename ql/src/codeql_ruby/typetracking/{TypeTrackerPrivate.qll => TypeTrackerSpecific.qll} (93%) diff --git a/ql/src/codeql_ruby/typetracking/TypeTracker.qll b/ql/src/codeql_ruby/typetracking/TypeTracker.qll index f8fd34723db..3dba23fc0c1 100644 --- a/ql/src/codeql_ruby/typetracking/TypeTracker.qll +++ b/ql/src/codeql_ruby/typetracking/TypeTracker.qll @@ -1,6 +1,6 @@ /** Step Summaries and Type Tracking */ -private import TypeTrackerPrivate +private import TypeTrackerSpecific /** * Any string that may appear as the name of a piece of content. This will usually include things like: @@ -71,8 +71,8 @@ module StepSummary { * Unlike `StepSummary::step`, this predicate does not compress * type-preserving steps. */ - predicate smallstep(Node nodeFrom, Node nodeTo, StepSummary summary) { - typePreservingStep(nodeFrom, nodeTo) and + predicate smallstep(Node nodeFrom, LocalSourceNode nodeTo, StepSummary summary) { + jumpStep(nodeFrom, nodeTo) and summary = LevelStep() or callStep(nodeFrom, nodeTo) and summary = CallStep() @@ -227,8 +227,8 @@ class TypeTracker extends TTypeTracker { pragma[inline] TypeTracker step(LocalSourceNode nodeFrom, LocalSourceNode nodeTo) { exists(StepSummary summary | - StepSummary::step(nodeFrom, nodeTo, summary) and - result = this.append(summary) + StepSummary::step(nodeFrom, pragma[only_bind_out](nodeTo), pragma[only_bind_into](summary)) and + result = this.append(pragma[only_bind_into](summary)) ) } @@ -263,7 +263,7 @@ class TypeTracker extends TTypeTracker { result = this.append(summary) ) or - typePreservingStep(nodeFrom, nodeTo) and + simpleLocalFlowStep(nodeFrom, nodeTo) and result = this } } @@ -370,8 +370,8 @@ class TypeBackTracker extends TTypeBackTracker { pragma[inline] TypeBackTracker step(LocalSourceNode nodeFrom, LocalSourceNode nodeTo) { exists(StepSummary summary | - StepSummary::step(nodeFrom, nodeTo, summary) and - this = result.prepend(summary) + StepSummary::step(pragma[only_bind_out](nodeFrom), nodeTo, pragma[only_bind_into](summary)) and + this = result.prepend(pragma[only_bind_into](summary)) ) } @@ -406,7 +406,7 @@ class TypeBackTracker extends TTypeBackTracker { this = result.prepend(summary) ) or - typePreservingStep(nodeFrom, nodeTo) and + simpleLocalFlowStep(nodeFrom, nodeTo) and this = result } } diff --git a/ql/src/codeql_ruby/typetracking/TypeTrackerPrivate.qll b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll similarity index 93% rename from ql/src/codeql_ruby/typetracking/TypeTrackerPrivate.qll rename to ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll index 447c60ffa93..2361fcaeaf4 100644 --- a/ql/src/codeql_ruby/typetracking/TypeTrackerPrivate.qll +++ b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll @@ -7,11 +7,9 @@ class Node = DataFlowPublic::Node; class LocalSourceNode = DataFlowPublic::LocalSourceNode; -/** Holds if it's reasonable to expect the data flow step from `nodeFrom` to `nodeTo` to preserve types. */ -predicate typePreservingStep(Node nodeFrom, Node nodeTo) { - DataFlowPrivate::simpleLocalFlowStep(nodeFrom, nodeTo) or - DataFlowPrivate::jumpStep(nodeFrom, nodeTo) -} +predicate simpleLocalFlowStep = DataFlowPrivate::simpleLocalFlowStep/2; + +predicate jumpStep = DataFlowPrivate::jumpStep/2; /** * Gets the name of a possible piece of content. This will usually include things like diff --git a/scripts/identical-files.json b/scripts/identical-files.json index 074df07cd9f..4b5fbb73347 100644 --- a/scripts/identical-files.json +++ b/scripts/identical-files.json @@ -10,5 +10,9 @@ "DataFlow": [ "codeql/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll", "ql/src/codeql_ruby/dataflow/internal/DataFlowImpl.qll" + ], + "TypeTracker": [ + "codeql/python/ql/src/experimental/typetracking/TypeTracker.qll", + "ql/src/codeql_ruby/typetracking/TypeTracker.qll" ] -} \ No newline at end of file +} From 2c0fc7d19378f60d1e137d8ef3ee5eea2ad670de Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 29 Apr 2021 15:34:10 +0100 Subject: [PATCH 09/66] parse integer permission args as ints instead of using regex matches --- .../security/cwe-732/WeakFilePermissions.ql | 53 +++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql index 0ac0b518aa6..d367bede0b2 100644 --- a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -14,7 +14,6 @@ private import codeql_ruby.dataflow.SSA private import codeql_ruby.dataflow.internal.DataFlowImpl as DataFlow // TODO: account for flows through tuple assignments - /** An expression referencing the File or FileUtils module */ class FileModuleAccess extends Expr { FileModuleAccess() { @@ -29,18 +28,52 @@ class FileModuleAccess extends Expr { } } +bindingset[p] +int world_permission(int p) { result = p % 8 } + +bindingset[p] +int group_permission(int p) { result = (p / 8) % 8 } + +bindingset[p] +string access(int p) { + p % 4 >= 2 and result = "writable" + or + p % 8 in [4, 5] and result = "readable" +} + +bindingset[s] +int parseInt(string s) { + exists(string values, string str | + s.matches("0b%") and values = "01" and str = s.suffix(2) + or + s.matches("0x%") and values = "0123456789abcdef" and str = s.suffix(2) + or + s.charAt(0) = "0" and not s.charAt(1) = ["b", "x"] and values = "01234567" and str = s.suffix(1) + or + s.charAt(0) != "0" and values = "0123456789" and str = s + | + result = + sum(int index, string c, int v, int exp | + c = str.replaceAll("_", "").charAt(index) and + v = values.indexOf(c.toLowerCase()) and + exp = str.replaceAll("_", "").length() - index - 1 + | + v * values.length().pow(exp) + ) + ) +} + /** An expression specifing a file permission that allows group/others read or write access */ class PermissivePermissionsExpr extends Expr { + // TODO: non-literal expressions? PermissivePermissionsExpr() { - this.(IntegerLiteral).getValueText().regexpMatch("0[0-7](([2-7].)|.[2-7])") + exists(int perm, string acc | + perm = parseInt(this.(IntegerLiteral).getValueText()) and + (acc = access(world_permission(perm)) or acc = access(group_permission(perm))) + ) or - this.(IntegerLiteral) - .getValueText() - .regexpMatch("0b[01]{3}+((1[01]{5}+)|([01]1[01]{4}+)|([01]{3}+1[01]{2}+)|([01]{4}+1[01]))") - or - // TODO: non-literal expressions? underscores? decimal/hex literals? // adding/setting read or write permissions for all/group/owner - this.(StringLiteral).getValueText().regexpMatch(".*[ago][^-=+]*[+=]*[rwxXst]*[rw].*") + this.(StringLiteral).getValueText().regexpMatch(".*[ago][^-=+]*[+=]*[xXst]*[rw].*") } } @@ -82,5 +115,5 @@ class PermissivePermissionsConfig extends DataFlow::Configuration { from DataFlow::PathNode source, DataFlow::PathNode sink, PermissivePermissionsConfig conf where conf.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "Overly permissive mask sets file to $@.", - source.getNode(), source.getNode().toString() \ No newline at end of file +select sink.getNode(), source, sink, "Overly permissive mask sets file to $@.", source.getNode(), + source.getNode().toString() From 1c89bbe18830ed9c9ffc39db2160be7d317f584e Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 29 Apr 2021 15:44:54 +0100 Subject: [PATCH 10/66] fix select format of rb/overly-permissive-file --- ql/src/queries/security/cwe-732/WeakFilePermissions.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql index d367bede0b2..cf8ba03b786 100644 --- a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -115,5 +115,5 @@ class PermissivePermissionsConfig extends DataFlow::Configuration { from DataFlow::PathNode source, DataFlow::PathNode sink, PermissivePermissionsConfig conf where conf.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "Overly permissive mask sets file to $@.", source.getNode(), +select sink, source, sink, "Overly permissive mask sets file to $@.", source.getNode(), source.getNode().toString() From 46a14b282606aec39b5903368b1f78144271a9c2 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 29 Apr 2021 15:54:22 +0100 Subject: [PATCH 11/66] move parseInt logic into getValue method predicate on IntegerLiteral --- ql/src/codeql_ruby/ast/Literal.qll | 27 +++++++++++++++++++ .../security/cwe-732/WeakFilePermissions.ql | 24 +---------------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/ql/src/codeql_ruby/ast/Literal.qll b/ql/src/codeql_ruby/ast/Literal.qll index ce0825cce92..615b0b16210 100644 --- a/ql/src/codeql_ruby/ast/Literal.qll +++ b/ql/src/codeql_ruby/ast/Literal.qll @@ -47,6 +47,33 @@ class IntegerLiteral extends NumericLiteral, TIntegerLiteral { final override string getValueText() { result = g.getValue() } + final int getValue() { + exists(string s, string values, string str | + s = this.getValueText() and + ( + s.matches("0b%") and values = "01" and str = s.suffix(2) + or + s.matches("0x%") and values = "0123456789abcdef" and str = s.suffix(2) + or + s.charAt(0) = "0" and + not s.charAt(1) = ["b", "x"] and + values = "01234567" and + str = s.suffix(1) + or + s.charAt(0) != "0" and values = "0123456789" and str = s + ) + | + result = + sum(int index, string c, int v, int exp | + c = str.replaceAll("_", "").charAt(index) and + v = values.indexOf(c.toLowerCase()) and + exp = str.replaceAll("_", "").length() - index - 1 + | + v * values.length().pow(exp) + ) + ) + } + final override string toString() { result = this.getValueText() } final override string getAPrimaryQlClass() { result = "IntegerLiteral" } diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql index cf8ba03b786..6296ca2dd84 100644 --- a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -41,34 +41,12 @@ string access(int p) { p % 8 in [4, 5] and result = "readable" } -bindingset[s] -int parseInt(string s) { - exists(string values, string str | - s.matches("0b%") and values = "01" and str = s.suffix(2) - or - s.matches("0x%") and values = "0123456789abcdef" and str = s.suffix(2) - or - s.charAt(0) = "0" and not s.charAt(1) = ["b", "x"] and values = "01234567" and str = s.suffix(1) - or - s.charAt(0) != "0" and values = "0123456789" and str = s - | - result = - sum(int index, string c, int v, int exp | - c = str.replaceAll("_", "").charAt(index) and - v = values.indexOf(c.toLowerCase()) and - exp = str.replaceAll("_", "").length() - index - 1 - | - v * values.length().pow(exp) - ) - ) -} - /** An expression specifing a file permission that allows group/others read or write access */ class PermissivePermissionsExpr extends Expr { // TODO: non-literal expressions? PermissivePermissionsExpr() { exists(int perm, string acc | - perm = parseInt(this.(IntegerLiteral).getValueText()) and + perm = this.(IntegerLiteral).getValue() and (acc = access(world_permission(perm)) or acc = access(group_permission(perm))) ) or From efa323c3045d97e0f09070a959a0841d6bc959d6 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 29 Apr 2021 16:08:42 +0100 Subject: [PATCH 12/66] rb/overly-permissive-file use QL bitwise operators --- ql/src/queries/security/cwe-732/WeakFilePermissions.ql | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql index 6296ca2dd84..c6d1760dc13 100644 --- a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -29,16 +29,17 @@ class FileModuleAccess extends Expr { } bindingset[p] -int world_permission(int p) { result = p % 8 } +int world_permission(int p) { result = p.bitAnd(7) } bindingset[p] -int group_permission(int p) { result = (p / 8) % 8 } +// 70 oct = 56 dec +int group_permission(int p) { result = p.bitAnd(56) } bindingset[p] string access(int p) { - p % 4 >= 2 and result = "writable" + p.bitAnd(2) != 0 and result = "writable" or - p % 8 in [4, 5] and result = "readable" + p.bitAnd(2) = 0 and p.bitAnd(4) != 0 and result = "readable" } /** An expression specifing a file permission that allows group/others read or write access */ From 35d5bae10ea5bf1cf2e7daf8b087c574833e1cb8 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 29 Apr 2021 16:16:09 +0100 Subject: [PATCH 13/66] run formatter --- ql/src/queries/security/cwe-732/WeakFilePermissions.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql index c6d1760dc13..c86d3459f0c 100644 --- a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -31,8 +31,8 @@ class FileModuleAccess extends Expr { bindingset[p] int world_permission(int p) { result = p.bitAnd(7) } -bindingset[p] // 70 oct = 56 dec +bindingset[p] int group_permission(int p) { result = p.bitAnd(56) } bindingset[p] From 05adfec03d4423fa4be98a5c9bb789409967f60b Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 29 Apr 2021 17:02:54 +0100 Subject: [PATCH 14/66] account for more patterns in IntegerLiteral.getValue --- ql/src/codeql_ruby/ast/Literal.qll | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/ql/src/codeql_ruby/ast/Literal.qll b/ql/src/codeql_ruby/ast/Literal.qll index 615b0b16210..a169c4f3780 100644 --- a/ql/src/codeql_ruby/ast/Literal.qll +++ b/ql/src/codeql_ruby/ast/Literal.qll @@ -51,15 +51,23 @@ class IntegerLiteral extends NumericLiteral, TIntegerLiteral { exists(string s, string values, string str | s = this.getValueText() and ( - s.matches("0b%") and values = "01" and str = s.suffix(2) + (s.matches("0b%") or s.matches("0B%")) and + values = "01" and + str = s.suffix(2) or - s.matches("0x%") and values = "0123456789abcdef" and str = s.suffix(2) + (s.matches("0x%") or s.matches("0X%")) and + values = "0123456789abcdef" and + str = s.suffix(2) or s.charAt(0) = "0" and - not s.charAt(1) = ["b", "x"] and + not s.charAt(1) = ["b", "B", "x", "X"] and values = "01234567" and str = s.suffix(1) or + (s.matches("0o%") or s.matches("0O%")) and + values = "01234567" and + str = s.suffix(2) + or s.charAt(0) != "0" and values = "0123456789" and str = s ) | From 43754528668aafaa2f6dddaa06fdf8fbed6d3cd8 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 29 Apr 2021 17:08:33 +0100 Subject: [PATCH 15/66] more IntegerLiteral.getValue improvements --- ql/src/codeql_ruby/ast/Literal.qll | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ql/src/codeql_ruby/ast/Literal.qll b/ql/src/codeql_ruby/ast/Literal.qll index a169c4f3780..fbf06f0e8cb 100644 --- a/ql/src/codeql_ruby/ast/Literal.qll +++ b/ql/src/codeql_ruby/ast/Literal.qll @@ -49,22 +49,22 @@ class IntegerLiteral extends NumericLiteral, TIntegerLiteral { final int getValue() { exists(string s, string values, string str | - s = this.getValueText() and + s = this.getValueText().toLowerCase() and ( - (s.matches("0b%") or s.matches("0B%")) and + s.matches("0b%") and values = "01" and str = s.suffix(2) or - (s.matches("0x%") or s.matches("0X%")) and + s.matches("0x%") and values = "0123456789abcdef" and str = s.suffix(2) or s.charAt(0) = "0" and - not s.charAt(1) = ["b", "B", "x", "X"] and + not s.charAt(1) = ["b", "x", "o"] and values = "01234567" and str = s.suffix(1) or - (s.matches("0o%") or s.matches("0O%")) and + s.matches("0o%") and values = "01234567" and str = s.suffix(2) or From 2c8a4f833fe252e42fba773be2077f53fc2226f6 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 29 Apr 2021 19:11:39 +0100 Subject: [PATCH 16/66] make rb/overly-permissive-file a proper path-problem --- .../security/cwe-732/WeakFilePermissions.ql | 3 ++- .../cwe-732/WeakFilePermissions.expected | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql index c86d3459f0c..13460d22603 100644 --- a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -10,6 +10,7 @@ */ import ruby +import codeql_ruby.dataflow.internal.DataFlowImpl::PathGraph private import codeql_ruby.dataflow.SSA private import codeql_ruby.dataflow.internal.DataFlowImpl as DataFlow @@ -94,5 +95,5 @@ class PermissivePermissionsConfig extends DataFlow::Configuration { from DataFlow::PathNode source, DataFlow::PathNode sink, PermissivePermissionsConfig conf where conf.hasFlowPath(source, sink) -select sink, source, sink, "Overly permissive mask sets file to $@.", source.getNode(), +select sink.getNode(), source, sink, "Overly permissive mask sets file to $@.", source.getNode(), source.getNode().toString() diff --git a/ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected b/ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected index 1b5d49b2d28..965851448ff 100644 --- a/ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected +++ b/ql/test/query-tests/security/cwe-732/WeakFilePermissions.expected @@ -1,3 +1,22 @@ +edges +| FilePermissions.rb:43:10:43:13 | 0777 : | FilePermissions.rb:44:19:44:22 | perm | +| FilePermissions.rb:43:10:43:13 | 0777 : | FilePermissions.rb:46:19:46:23 | perm2 | +| FilePermissions.rb:48:10:48:26 | "u=wrx,g=rwx,o=x" : | FilePermissions.rb:50:19:50:23 | perm2 | +nodes +| FilePermissions.rb:4:19:4:22 | 0222 | semmle.label | 0222 | +| FilePermissions.rb:5:19:5:22 | 0622 | semmle.label | 0622 | +| FilePermissions.rb:6:19:6:22 | 0755 | semmle.label | 0755 | +| FilePermissions.rb:7:19:7:22 | 0777 | semmle.label | 0777 | +| FilePermissions.rb:24:13:24:16 | 0755 | semmle.label | 0755 | +| FilePermissions.rb:43:10:43:13 | 0777 : | semmle.label | 0777 : | +| FilePermissions.rb:44:19:44:22 | perm | semmle.label | perm | +| FilePermissions.rb:46:19:46:23 | perm2 | semmle.label | perm2 | +| FilePermissions.rb:48:10:48:26 | "u=wrx,g=rwx,o=x" : | semmle.label | "u=wrx,g=rwx,o=x" : | +| FilePermissions.rb:50:19:50:23 | perm2 | semmle.label | perm2 | +| FilePermissions.rb:51:19:51:29 | "u=rwx,o+r" | semmle.label | "u=rwx,o+r" | +| FilePermissions.rb:53:19:53:24 | "a+rw" | semmle.label | "a+rw" | +| FilePermissions.rb:57:16:57:19 | 0755 | semmle.label | 0755 | +#select | FilePermissions.rb:4:19:4:22 | 0222 | FilePermissions.rb:4:19:4:22 | 0222 | FilePermissions.rb:4:19:4:22 | 0222 | Overly permissive mask sets file to $@. | FilePermissions.rb:4:19:4:22 | 0222 | 0222 | | FilePermissions.rb:5:19:5:22 | 0622 | FilePermissions.rb:5:19:5:22 | 0622 | FilePermissions.rb:5:19:5:22 | 0622 | Overly permissive mask sets file to $@. | FilePermissions.rb:5:19:5:22 | 0622 | 0622 | | FilePermissions.rb:6:19:6:22 | 0755 | FilePermissions.rb:6:19:6:22 | 0755 | FilePermissions.rb:6:19:6:22 | 0755 | Overly permissive mask sets file to $@. | FilePermissions.rb:6:19:6:22 | 0755 | 0755 | From 37c8d8a2523eb66b0a9d44fcd6c086ffac23e609 Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Fri, 30 Apr 2021 14:41:50 +0100 Subject: [PATCH 17/66] Rename getCallable to getTarget --- ql/src/codeql_ruby/dataflow/internal/DataFlowDispatch.qll | 2 +- ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ql/src/codeql_ruby/dataflow/internal/DataFlowDispatch.qll b/ql/src/codeql_ruby/dataflow/internal/DataFlowDispatch.qll index a539e18b069..916ea836e63 100644 --- a/ql/src/codeql_ruby/dataflow/internal/DataFlowDispatch.qll +++ b/ql/src/codeql_ruby/dataflow/internal/DataFlowDispatch.qll @@ -41,7 +41,7 @@ class DataFlowCallable = CfgScope; class DataFlowCall extends CfgNodes::ExprNodes::CallCfgNode { DataFlowCallable getEnclosingCallable() { result = this.getScope() } - DataFlowCallable getCallable() { + DataFlowCallable getTarget() { // TODO: this is a placeholder that finds a method with the same name, iff it's uniquely named. result = unique(DataFlowCallable c | c.(Method).getName() = this.getNode().(MethodCall).getMethodName()) diff --git a/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll index 2361fcaeaf4..b7a512ec8ee 100644 --- a/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll +++ b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll @@ -24,7 +24,7 @@ predicate callStep( DataFlowPrivate::ArgumentNode nodeFrom, DataFlowPrivate::ExplicitParameterNode nodeTo ) { exists(DataFlowDispatch::DataFlowCall call, DataFlowDispatch::DataFlowCallable callable, int i | - call.getCallable() = callable and + call.getTarget() = callable and nodeFrom.argumentOf(call, i) and nodeTo.isParameterOf(callable, i) ) @@ -33,7 +33,7 @@ predicate callStep( /** Holds if `nodeFrom` steps to `nodeTo` by being returned from a call. */ predicate returnStep(DataFlowPrivate::ReturnNode nodeFrom, Node nodeTo) { exists(DataFlowDispatch::DataFlowCall call | - nodeFrom.getEnclosingCallable() = call.getCallable() and + nodeFrom.getEnclosingCallable() = call.getTarget() and nodeTo.asExpr().getNode() = call.getNode() ) } From 5dc910d0dbd05c6f7b50cb7ae0fef19f0584cc6a Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Fri, 30 Apr 2021 15:05:12 +0100 Subject: [PATCH 18/66] Move `track` predicate to LocalSourceNode --- .../dataflow/internal/DataFlowPublic.qll | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll b/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll index 0d957f7dd35..775d0bde444 100644 --- a/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll +++ b/ql/src/codeql_ruby/dataflow/internal/DataFlowPublic.qll @@ -37,14 +37,6 @@ class Node extends TNode { ) { getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } - - /** - * Gets a node that this node may flow to using one heap and/or interprocedural step. - * - * See `TypeTracker` for more details about how to use this. - */ - pragma[inline] - LocalSourceNode track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) } } /** @@ -91,6 +83,14 @@ class LocalSourceNode extends Node { /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ pragma[inline] predicate flowsTo(Node nodeTo) { hasLocalSource(nodeTo, this) } + + /** + * Gets a node that this node may flow to using one heap and/or interprocedural step. + * + * See `TypeTracker` for more details about how to use this. + */ + pragma[inline] + LocalSourceNode track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) } } predicate hasLocalSource(Node sink, Node source) { From 35ee62c689e9789e85f0afaf70287877abdd6608 Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Tue, 4 May 2021 11:31:03 +0100 Subject: [PATCH 19/66] Use splitting-aware nodes for type-tracking store/load steps --- .../typetracking/TypeTrackerSpecific.qll | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll index b7a512ec8ee..eb5db83653e 100644 --- a/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll +++ b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll @@ -2,6 +2,7 @@ private import codeql_ruby.AST as AST private import codeql_ruby.dataflow.internal.DataFlowPublic as DataFlowPublic private import codeql_ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate private import codeql_ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch +private import codeql_ruby.controlflow.CfgNodes class Node = DataFlowPublic::Node; @@ -71,11 +72,14 @@ predicate returnStep(DataFlowPrivate::ReturnNode nodeFrom, Node nodeTo) { */ predicate basicStoreStep(Node nodeFrom, LocalSourceNode nodeTo, string content) { // TODO: support SetterMethodCall inside TuplePattern - exists(AST::Assignment assignment, AST::SetterMethodCall call, DataFlowPublic::ExprNode receiver | - assignment.getLeftOperand() = call and - content = getSetterCallAttributeName(call) and - receiver.getExprNode().getNode() = call.getReceiver() and - assignment.getRightOperand() = nodeFrom.(DataFlowPublic::ExprNode).getExprNode().getNode() and + exists( + ExprNodes::AssignmentCfgNode assignment, ExprNodes::CallCfgNode call, + DataFlowPublic::ExprNode receiver + | + assignment.getLhs() = call and + content = getSetterCallAttributeName(call.getExpr()) and + receiver.getExprNode().getNode() = call.getExpr().(AST::SetterMethodCall).getReceiver() and + assignment.getRhs() = nodeFrom.(DataFlowPublic::ExprNode).getExprNode() and nodeTo.flowsTo(receiver) ) } @@ -101,11 +105,11 @@ private string getSetterCallAttributeName(AST::SetterMethodCall call) { * Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`. */ predicate basicLoadStep(Node nodeFrom, Node nodeTo, string content) { - exists(AST::MethodCall call | - call.getNumberOfArguments() = 0 and - content = call.getMethodName() and - nodeFrom.asExpr().getNode() = call.getReceiver() and - nodeTo.asExpr().getNode() = call + exists(ExprNodes::CallCfgNode call | + call.getExpr().getNumberOfArguments() = 0 and + content = call.getExpr().(AST::MethodCall).getMethodName() and + nodeFrom.asExpr().getNode() = call.getExpr().(AST::MethodCall).getReceiver() and + nodeTo.asExpr() = call ) } From 53deede8ab9235db58cb3d5394d927e587d9be70 Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Tue, 4 May 2021 11:32:57 +0100 Subject: [PATCH 20/66] Remove unnecessary local flow inside type-tracking store step --- ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll index eb5db83653e..abef22a19ea 100644 --- a/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll +++ b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll @@ -80,7 +80,7 @@ predicate basicStoreStep(Node nodeFrom, LocalSourceNode nodeTo, string content) content = getSetterCallAttributeName(call.getExpr()) and receiver.getExprNode().getNode() = call.getExpr().(AST::SetterMethodCall).getReceiver() and assignment.getRhs() = nodeFrom.(DataFlowPublic::ExprNode).getExprNode() and - nodeTo.flowsTo(receiver) + nodeTo = receiver ) } From b16b95e2f73a41e937a10a190e2f69e22c27aa14 Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Wed, 5 May 2021 12:12:45 +0100 Subject: [PATCH 21/66] Fix type-tracking load/store steps --- ql/src/codeql_ruby/controlflow/CfgNodes.qll | 5 +++++ .../typetracking/TypeTrackerSpecific.qll | 15 ++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ql/src/codeql_ruby/controlflow/CfgNodes.qll b/ql/src/codeql_ruby/controlflow/CfgNodes.qll index 10449ed7c91..2c6f9f7a809 100644 --- a/ql/src/codeql_ruby/controlflow/CfgNodes.qll +++ b/ql/src/codeql_ruby/controlflow/CfgNodes.qll @@ -247,6 +247,11 @@ module ExprNodes { override predicate relevantChild(Expr e) { e = this.getValue() or e = this.getBranch(_) } } + /** A control-flow node that wraps a `MethodCall` AST expression. */ + class MethodCallCfgNode extends CallCfgNode { + MethodCallCfgNode() { this.getExpr() instanceof MethodCall } + } + /** A control-flow node that wraps a `CaseExpr` AST expression. */ class CaseExprCfgNode extends ExprCfgNode { override CaseExprChildMapping e; diff --git a/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll index abef22a19ea..5c96fe28029 100644 --- a/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll +++ b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll @@ -72,15 +72,12 @@ predicate returnStep(DataFlowPrivate::ReturnNode nodeFrom, Node nodeTo) { */ predicate basicStoreStep(Node nodeFrom, LocalSourceNode nodeTo, string content) { // TODO: support SetterMethodCall inside TuplePattern - exists( - ExprNodes::AssignmentCfgNode assignment, ExprNodes::CallCfgNode call, - DataFlowPublic::ExprNode receiver - | + exists(ExprNodes::AssignmentCfgNode assignment, ExprNodes::CallCfgNode call | assignment.getLhs() = call and content = getSetterCallAttributeName(call.getExpr()) and - receiver.getExprNode().getNode() = call.getExpr().(AST::SetterMethodCall).getReceiver() and - assignment.getRhs() = nodeFrom.(DataFlowPublic::ExprNode).getExprNode() and - nodeTo = receiver + nodeTo.(DataFlowPublic::ExprNode).getExprNode() = call.getReceiver() and + call.getExpr() instanceof AST::SetterMethodCall and + assignment.getRhs() = nodeFrom.(DataFlowPublic::ExprNode).getExprNode() ) } @@ -105,10 +102,10 @@ private string getSetterCallAttributeName(AST::SetterMethodCall call) { * Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`. */ predicate basicLoadStep(Node nodeFrom, Node nodeTo, string content) { - exists(ExprNodes::CallCfgNode call | + exists(ExprNodes::MethodCallCfgNode call | call.getExpr().getNumberOfArguments() = 0 and content = call.getExpr().(AST::MethodCall).getMethodName() and - nodeFrom.asExpr().getNode() = call.getExpr().(AST::MethodCall).getReceiver() and + nodeFrom.asExpr() = call.getReceiver() and nodeTo.asExpr() = call ) } From 3a3586f14bae6870c943d699d40720e7d98f8236 Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Wed, 5 May 2021 14:49:24 +0100 Subject: [PATCH 22/66] Restrict type to MethodCallCfgNode --- ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll index 5c96fe28029..3f05a429b41 100644 --- a/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll +++ b/ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll @@ -72,7 +72,7 @@ predicate returnStep(DataFlowPrivate::ReturnNode nodeFrom, Node nodeTo) { */ predicate basicStoreStep(Node nodeFrom, LocalSourceNode nodeTo, string content) { // TODO: support SetterMethodCall inside TuplePattern - exists(ExprNodes::AssignmentCfgNode assignment, ExprNodes::CallCfgNode call | + exists(ExprNodes::AssignmentCfgNode assignment, ExprNodes::MethodCallCfgNode call | assignment.getLhs() = call and content = getSetterCallAttributeName(call.getExpr()) and nodeTo.(DataFlowPublic::ExprNode).getExprNode() = call.getReceiver() and From f6c8b07f4f92c8d3b5fcb6cef37223a9a313b71d Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 4 May 2021 21:03:31 +0100 Subject: [PATCH 23/66] rb/summary/lines-of-code --- ql/src/queries/summary/LinesOfCode.ql | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 ql/src/queries/summary/LinesOfCode.ql diff --git a/ql/src/queries/summary/LinesOfCode.ql b/ql/src/queries/summary/LinesOfCode.ql new file mode 100644 index 00000000000..958a931a16d --- /dev/null +++ b/ql/src/queries/summary/LinesOfCode.ql @@ -0,0 +1,13 @@ +/** + * @id rb/summary/lines-of-code + * @name Total lines of Ruby code in the database + * @description The total number of lines of Ruby code across all files, + * including vendored code, tests. This query counts the lines of code, + * excluding whitespace or comments. + * @kind metric + * @tags summary + */ + +import ruby + +select sum(File f | | f.getNumberOfLinesOfCode()) From 98a4f4c5b97f708986771a3ef1d2615213eef315 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 4 May 2021 21:03:55 +0100 Subject: [PATCH 24/66] rb/summary/lines-of-user-code --- ql/src/codeql/files/FileSystem.qll | 3 +++ ql/src/queries/summary/LinesOfUserCode.ql | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 ql/src/queries/summary/LinesOfUserCode.ql diff --git a/ql/src/codeql/files/FileSystem.qll b/ql/src/codeql/files/FileSystem.qll index 372a53b53c0..d9da4d01cac 100644 --- a/ql/src/codeql/files/FileSystem.qll +++ b/ql/src/codeql/files/FileSystem.qll @@ -190,4 +190,7 @@ class File extends Container, @file { /** Gets the number of lines of comments in this file. */ int getNumberOfLinesOfComments() { result = count(int line | this.line(line, true)) } + + /** Holds if this file was extracted from ordinary source code. */ + predicate fromSource() { files(this, _, _, _, 1) } } diff --git a/ql/src/queries/summary/LinesOfUserCode.ql b/ql/src/queries/summary/LinesOfUserCode.ql new file mode 100644 index 00000000000..c7dbb7ee5ba --- /dev/null +++ b/ql/src/queries/summary/LinesOfUserCode.ql @@ -0,0 +1,17 @@ +/** + * @id rb/summary/lines-of-user-code + * @name Lines of authored Ruby code in the database + * @description The total number of lines of Ruby code across files, excluding library and generated code. + * @kind metric + * @tags summary + */ + +import ruby + +select sum(File f | + f.fromSource() and + exists(f.getRelativePath()) and + not f.getAbsolutePath().matches("%/vendor/%") + | + f.getNumberOfLinesOfCode() + ) From e5896047d8b060159e2f2f5c2b9d2817d1de4427 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 6 May 2021 19:50:28 +0100 Subject: [PATCH 25/66] summary LOC query tests --- ql/test/query-tests/summary/LinesOfCode.expected | 1 + ql/test/query-tests/summary/LinesOfCode.qlref | 1 + ql/test/query-tests/summary/LinesOfUserCode.expected | 1 + ql/test/query-tests/summary/LinesOfUserCode.qlref | 1 + ql/test/query-tests/summary/src/foo.rb | 11 +++++++++++ ql/test/query-tests/summary/src/vendor/cache/lib.rb | 9 +++++++++ 6 files changed, 24 insertions(+) create mode 100644 ql/test/query-tests/summary/LinesOfCode.expected create mode 100644 ql/test/query-tests/summary/LinesOfCode.qlref create mode 100644 ql/test/query-tests/summary/LinesOfUserCode.expected create mode 100644 ql/test/query-tests/summary/LinesOfUserCode.qlref create mode 100644 ql/test/query-tests/summary/src/foo.rb create mode 100644 ql/test/query-tests/summary/src/vendor/cache/lib.rb diff --git a/ql/test/query-tests/summary/LinesOfCode.expected b/ql/test/query-tests/summary/LinesOfCode.expected new file mode 100644 index 00000000000..f17cce5aa70 --- /dev/null +++ b/ql/test/query-tests/summary/LinesOfCode.expected @@ -0,0 +1 @@ +| 9 | diff --git a/ql/test/query-tests/summary/LinesOfCode.qlref b/ql/test/query-tests/summary/LinesOfCode.qlref new file mode 100644 index 00000000000..84278cfc96b --- /dev/null +++ b/ql/test/query-tests/summary/LinesOfCode.qlref @@ -0,0 +1 @@ +queries/summary/LinesOfCode.ql \ No newline at end of file diff --git a/ql/test/query-tests/summary/LinesOfUserCode.expected b/ql/test/query-tests/summary/LinesOfUserCode.expected new file mode 100644 index 00000000000..69f8503f966 --- /dev/null +++ b/ql/test/query-tests/summary/LinesOfUserCode.expected @@ -0,0 +1 @@ +| 5 | diff --git a/ql/test/query-tests/summary/LinesOfUserCode.qlref b/ql/test/query-tests/summary/LinesOfUserCode.qlref new file mode 100644 index 00000000000..4114db632a2 --- /dev/null +++ b/ql/test/query-tests/summary/LinesOfUserCode.qlref @@ -0,0 +1 @@ +queries/summary/LinesOfUserCode.ql \ No newline at end of file diff --git a/ql/test/query-tests/summary/src/foo.rb b/ql/test/query-tests/summary/src/foo.rb new file mode 100644 index 00000000000..2f0f2acc09a --- /dev/null +++ b/ql/test/query-tests/summary/src/foo.rb @@ -0,0 +1,11 @@ +# comment + +def hello + p "hello foo" +end + +# another one + +hello + +p "more code here" diff --git a/ql/test/query-tests/summary/src/vendor/cache/lib.rb b/ql/test/query-tests/summary/src/vendor/cache/lib.rb new file mode 100644 index 00000000000..f75db7941db --- /dev/null +++ b/ql/test/query-tests/summary/src/vendor/cache/lib.rb @@ -0,0 +1,9 @@ +# comment + +def hello + p "hello lib" +end + +# another one + +hello From c38453305f07a35d7e1b8c5b5da53ee9c0810066 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 5 May 2021 15:45:17 +0100 Subject: [PATCH 26/66] add diagnostics table to dbscheme --- generator/src/main.rs | 52 +++++++++++++++++++++++++++++++++++++++++++ ql/src/ruby.dbscheme | 9 ++++++++ 2 files changed, 61 insertions(+) diff --git a/generator/src/main.rs b/generator/src/main.rs index b3e73c5a445..6f5666c9033 100644 --- a/generator/src/main.rs +++ b/generator/src/main.rs @@ -148,6 +148,7 @@ fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec = Set::new(); let token_kinds: Map<&str, usize> = nodes @@ -590,6 +591,57 @@ fn create_source_location_prefix_table<'a>() -> dbscheme::Entry<'a> { }) } +fn create_diagnostics_table<'a>() -> dbscheme::Entry<'a> { + dbscheme::Entry::Table(dbscheme::Table { + name: "diagnostics", + keysets: None, + columns: vec![ + dbscheme::Column { + unique: true, + db_type: dbscheme::DbColumnType::Int, + name: "id", + ql_type: ql::Type::AtType("diagnostic"), + ql_type_is_ref: false, + }, + dbscheme::Column { + unique: false, + db_type: dbscheme::DbColumnType::Int, + name: "severity", + ql_type: ql::Type::Int, + ql_type_is_ref: true, + }, + dbscheme::Column { + unique: false, + db_type: dbscheme::DbColumnType::String, + name: "error_tag", + ql_type: ql::Type::String, + ql_type_is_ref: true, + }, + dbscheme::Column { + unique: false, + db_type: dbscheme::DbColumnType::String, + name: "error_message", + ql_type: ql::Type::String, + ql_type_is_ref: true, + }, + dbscheme::Column { + unique: false, + db_type: dbscheme::DbColumnType::String, + name: "full_error_message", + ql_type: ql::Type::String, + ql_type_is_ref: true, + }, + dbscheme::Column { + unique: false, + db_type: dbscheme::DbColumnType::Int, + name: "location", + ql_type: ql::Type::AtType("location_default"), + ql_type_is_ref: true, + }, + ], + }) +} + fn main() { tracing_subscriber::fmt() .with_target(false) diff --git a/ql/src/ruby.dbscheme b/ql/src/ruby.dbscheme index 8725deeb2fa..dcbc1684061 100644 --- a/ql/src/ruby.dbscheme +++ b/ql/src/ruby.dbscheme @@ -46,6 +46,15 @@ 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 +); + @underscore_arg = @assignment | @binary | @conditional | @operator_assignment | @range | @unary | @underscore_primary @underscore_lhs = @call | @element_reference | @scope_resolution | @token_false | @token_nil | @token_true | @underscore_variable From 3a1dff1c956c087dad2f9162b3446f2733c87cc4 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 6 May 2021 14:58:57 +0100 Subject: [PATCH 27/66] start writing diagnostics entries for parse errors --- extractor/src/extractor.rs | 61 ++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/extractor/src/extractor.rs b/extractor/src/extractor.rs index 1f282d8211c..12671cb796a 100644 --- a/extractor/src/extractor.rs +++ b/extractor/src/extractor.rs @@ -269,21 +269,70 @@ struct Visitor<'a> { } impl Visitor<'_> { + fn record_error( + &mut self, + node: Node, + severity: usize, + error_tag: String, + error_message: String, + full_error_message: String, + ) { + let (start_line, start_column, end_line, end_column) = location_for(&self.source, node); + let loc = self.trap_writer.location( + self.file_label, + start_line, + start_column, + end_line, + end_column, + ); + let id = self.trap_writer.fresh_id(); + self.trap_writer.add_tuple( + "diagnostics", + vec![ + Arg::Label(id), + Arg::Int(severity), + Arg::String(error_tag), + Arg::String(error_message), + Arg::String(full_error_message), + Arg::Label(loc), + ], + ); + } + fn enter_node(&mut self, node: Node) -> bool { if node.is_error() { - error!( - "{}:{}: parse error", + let short_err = "parse error"; + let full_err = format!( + "{}:{}: {}", &self.path, - node.start_position().row + 1 + node.start_position().row + 1, + short_err + ); + error!("{}", full_err); + self.record_error( + node, + 4, + "parse_error".to_string(), + short_err.to_string(), + full_err, ); return false; } if node.is_missing() { - error!( - "{}:{}: parse error: expecting '{}'", + let short_err = format!("parse error: expecting '{}'", node.kind()); + let full_err = format!( + "{}:{}: {}", &self.path, node.start_position().row + 1, - node.kind() + short_err + ); + error!("{}", full_err); + self.record_error( + node, + 4, + "parse_error".to_string(), + short_err.to_string(), + full_err, ); return false; } From 272aec27f2843f59137b22392241cdfd87472fb8 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 6 May 2021 23:47:37 +0100 Subject: [PATCH 28/66] clean up the parse_error writing code --- extractor/src/extractor.rs | 62 +++++++++++--------------------------- 1 file changed, 18 insertions(+), 44 deletions(-) diff --git a/extractor/src/extractor.rs b/extractor/src/extractor.rs index 12671cb796a..c6574140276 100644 --- a/extractor/src/extractor.rs +++ b/extractor/src/extractor.rs @@ -269,14 +269,20 @@ struct Visitor<'a> { } impl Visitor<'_> { - fn record_error( - &mut self, - node: Node, - severity: usize, - error_tag: String, - error_message: String, - full_error_message: String, - ) { + fn record_parse_error(&mut self, node: Node) { + let error_message = if node.is_missing() { + format!("parse error: expecting '{}'", node.kind()) + } else { + "parse error".to_string() + }; + let full_error_message = format!( + "{}:{}: {}", + &self.path, + node.start_position().row + 1, + error_message + ); + error!("{}", full_error_message); + let (start_line, start_column, end_line, end_column) = location_for(&self.source, node); let loc = self.trap_writer.location( self.file_label, @@ -290,8 +296,8 @@ impl Visitor<'_> { "diagnostics", vec![ Arg::Label(id), - Arg::Int(severity), - Arg::String(error_tag), + Arg::Int(4), + Arg::String("parse_error".to_string()), Arg::String(error_message), Arg::String(full_error_message), Arg::Label(loc), @@ -300,40 +306,8 @@ impl Visitor<'_> { } fn enter_node(&mut self, node: Node) -> bool { - if node.is_error() { - let short_err = "parse error"; - let full_err = format!( - "{}:{}: {}", - &self.path, - node.start_position().row + 1, - short_err - ); - error!("{}", full_err); - self.record_error( - node, - 4, - "parse_error".to_string(), - short_err.to_string(), - full_err, - ); - return false; - } - if node.is_missing() { - let short_err = format!("parse error: expecting '{}'", node.kind()); - let full_err = format!( - "{}:{}: {}", - &self.path, - node.start_position().row + 1, - short_err - ); - error!("{}", full_err); - self.record_error( - node, - 4, - "parse_error".to_string(), - short_err.to_string(), - full_err, - ); + if node.is_error() || node.is_missing() { + self.record_parse_error(node); return false; } From d223851429c1e9b75016297539a976159a7dfc13 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 6 May 2021 23:11:58 +0100 Subject: [PATCH 29/66] add Diagnostics.qll --- ql/src/codeql_ruby/Diagnostics.qll | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 ql/src/codeql_ruby/Diagnostics.qll diff --git a/ql/src/codeql_ruby/Diagnostics.qll b/ql/src/codeql_ruby/Diagnostics.qll new file mode 100644 index 00000000000..4e35a9a5dd1 --- /dev/null +++ b/ql/src/codeql_ruby/Diagnostics.qll @@ -0,0 +1,31 @@ +private import codeql.Locations + +/** A diagnostic emitted during extraction, such as a parse error */ +class Diagnostic extends @diagnostic { + /** + * Gets the numerical severity level associated with this diagnostic. + */ + int getSeverity() { diagnostics(this, result, _, _, _, _) } + + /** Gets the error code associated with this diagnostic, e.g. parse_error. */ + string getTag() { diagnostics(this, _, result, _, _, _) } + + /** + * Gets the error message text associated with this diagnostic. + */ + string getMessage() { diagnostics(this, _, _, result, _, _) } + + /** + * Gets the full error message text associated with this diagnostic. + */ + string getFullMessage() { diagnostics(this, _, _, _, result, _) } + + /** Gets the source location of this diagnostic. */ + Location getLocation() { diagnostics(this, _, _, _, _, result) } + + string toString() { result = this.getMessage() } +} + +class ExtractionError extends Diagnostic { + ExtractionError() { this.getTag() = "parse_error" } +} \ No newline at end of file From 54266eca3359ddec14cbfdebf8a4682692f0035e Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 7 May 2021 00:17:12 +0100 Subject: [PATCH 30/66] rb/diagnostics/files-extracted-with-errors --- .../diagnostics/FilesExtractedWithErrors.ql | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 ql/src/queries/diagnostics/FilesExtractedWithErrors.ql diff --git a/ql/src/queries/diagnostics/FilesExtractedWithErrors.ql b/ql/src/queries/diagnostics/FilesExtractedWithErrors.ql new file mode 100644 index 00000000000..8db409eefd1 --- /dev/null +++ b/ql/src/queries/diagnostics/FilesExtractedWithErrors.ql @@ -0,0 +1,14 @@ +/** + * @name Files extracted with errors + * @description Lists files that were extracted, but may be incomplete due to + * extraction errors. + * @kind diagnostic + * @id rb/diagnostics/files-extracted-with-errors + */ + +import ruby +import codeql_ruby.Diagnostics + +from File f +where exists(ExtractionError e | e.getLocation().getFile() = f) +select f, "" From e7285babf05151a8a96d4213a979d2cc7a4cad1b Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 7 May 2021 00:17:58 +0100 Subject: [PATCH 31/66] rb/diagnostics/successfully-extracted-files --- .../diagnostics/SuccessfullyExtractedFiles.ql | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 ql/src/queries/diagnostics/SuccessfullyExtractedFiles.ql diff --git a/ql/src/queries/diagnostics/SuccessfullyExtractedFiles.ql b/ql/src/queries/diagnostics/SuccessfullyExtractedFiles.ql new file mode 100644 index 00000000000..f7c3bbd14af --- /dev/null +++ b/ql/src/queries/diagnostics/SuccessfullyExtractedFiles.ql @@ -0,0 +1,14 @@ +/** + * @name Successfully extracted files + * @description Lists all files that were extracted without encountering an + * error in the file. + * @kind diagnostic + * @id rb/diagnostics/successfully-extracted-files + */ + +import ruby +import codeql_ruby.Diagnostics + +from File f +where not exists(ExtractionError e | e.getLocation().getFile() = f) +select f, "" From 804198cd37fc9275642cabebb62d5924ac04acb0 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 7 May 2021 00:22:22 +0100 Subject: [PATCH 32/66] rb/summary/number-of-successfully-extracted-files --- .../summary/NumberOfSuccesfullyExtractedFiles.ql | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 ql/src/queries/summary/NumberOfSuccesfullyExtractedFiles.ql diff --git a/ql/src/queries/summary/NumberOfSuccesfullyExtractedFiles.ql b/ql/src/queries/summary/NumberOfSuccesfullyExtractedFiles.ql new file mode 100644 index 00000000000..e89f1350962 --- /dev/null +++ b/ql/src/queries/summary/NumberOfSuccesfullyExtractedFiles.ql @@ -0,0 +1,13 @@ +/** + * @id rb/summary/number-of-successfully-extracted-files + * @name Total number of files that were extracted without error. + * @description The total number of Ruby code files that we extracted without + * encountering any extraction errors + * @kind metric + * @tags summary + */ + +import ruby +import codeql_ruby.Diagnostics + +select count(File f | not exists(ExtractionError e | e.getLocation().getFile() = f)) From 31b8913ffd45466b66275464283f89822437701a Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 7 May 2021 00:23:56 +0100 Subject: [PATCH 33/66] rb/summary/number-of-successfully-extracted-files FIXUP --- ql/src/queries/summary/NumberOfSuccesfullyExtractedFiles.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/src/queries/summary/NumberOfSuccesfullyExtractedFiles.ql b/ql/src/queries/summary/NumberOfSuccesfullyExtractedFiles.ql index e89f1350962..36a584e2271 100644 --- a/ql/src/queries/summary/NumberOfSuccesfullyExtractedFiles.ql +++ b/ql/src/queries/summary/NumberOfSuccesfullyExtractedFiles.ql @@ -1,6 +1,6 @@ /** * @id rb/summary/number-of-successfully-extracted-files - * @name Total number of files that were extracted without error. + * @name Total number of files that were extracted without error * @description The total number of Ruby code files that we extracted without * encountering any extraction errors * @kind metric From a7873f9023b10ca6784f0e62cdfacf2d2b1f0bfa Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 7 May 2021 00:24:13 +0100 Subject: [PATCH 34/66] rb/summary/number-of-files-extracted-with-errors --- .../summary/NumberOfFilesExtractedWithErrors.ql | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql diff --git a/ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql b/ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql new file mode 100644 index 00000000000..eb871a4086d --- /dev/null +++ b/ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql @@ -0,0 +1,13 @@ +/** + * @id rb/summary/number-of-files-extracted-with-errors + * @name Total number of files that were extracted with errors + * @description The total number of Ruby code files that we extracted, but where + * at least one extraction error occurred in the process. + * @kind metric + * @tags summary + */ + +import ruby +import codeql_ruby.Diagnostics + +select count(File f | exists(ExtractionError e | e.getLocation().getFile() = f)) From 269ae8331b147971c2ae4d4cdd52dda6ead76c30 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 7 May 2021 17:56:50 +0100 Subject: [PATCH 35/66] record 'unknown table type' extraction errors --- extractor/src/extractor.rs | 56 ++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/extractor/src/extractor.rs b/extractor/src/extractor.rs index c6574140276..83948ec887e 100644 --- a/extractor/src/extractor.rs +++ b/extractor/src/extractor.rs @@ -269,6 +269,29 @@ struct Visitor<'a> { } impl Visitor<'_> { + fn record_error( + &mut self, + severity: usize, + error_tag: String, + error_message: String, + full_error_message: String, + loc: Label, + ) { + error!("{}", full_error_message); + let id = self.trap_writer.fresh_id(); + self.trap_writer.add_tuple( + "diagnostics", + vec![ + Arg::Label(id), + Arg::Int(severity), + Arg::String(error_tag), + Arg::String(error_message), + Arg::String(full_error_message), + Arg::Label(loc), + ], + ); + } + fn record_parse_error(&mut self, node: Node) { let error_message = if node.is_missing() { format!("parse error: expecting '{}'", node.kind()) @@ -281,7 +304,6 @@ impl Visitor<'_> { node.start_position().row + 1, error_message ); - error!("{}", full_error_message); let (start_line, start_column, end_line, end_column) = location_for(&self.source, node); let loc = self.trap_writer.location( @@ -291,17 +313,12 @@ impl Visitor<'_> { end_line, end_column, ); - let id = self.trap_writer.fresh_id(); - self.trap_writer.add_tuple( - "diagnostics", - vec![ - Arg::Label(id), - Arg::Int(4), - Arg::String("parse_error".to_string()), - Arg::String(error_message), - Arg::String(full_error_message), - Arg::Label(loc), - ], + self.record_error( + 4, + "parse_error".to_string(), + error_message, + full_error_message, + loc, ); } @@ -392,12 +409,21 @@ impl Visitor<'_> { } } _ => { - error!( - "{}:{}: unknown table type: '{}'", + let error_message = format!("unknown table type: '{}'", node.kind()); + let full_error_message = format!( + "{}:{}: {}", &self.path, node.start_position().row + 1, - node.kind() + error_message ); + self.record_error( + 4, + "parse_error".to_string(), + error_message, + full_error_message, + loc, + ); + valid = false; } } From 48add9ffbc9b4ffb4424f249d83ec21babf84172 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Mon, 10 May 2021 11:00:59 +0100 Subject: [PATCH 36/66] remove internal import in rb/overly-permissive-file --- ql/src/queries/security/cwe-732/WeakFilePermissions.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql index 13460d22603..79fd3f8b663 100644 --- a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -10,9 +10,9 @@ */ import ruby -import codeql_ruby.dataflow.internal.DataFlowImpl::PathGraph +import codeql_ruby.DataFlow +import DataFlow::PathGraph private import codeql_ruby.dataflow.SSA -private import codeql_ruby.dataflow.internal.DataFlowImpl as DataFlow // TODO: account for flows through tuple assignments /** An expression referencing the File or FileUtils module */ From 2154b7df3000866913846e9c5989fbfe698aade3 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Mon, 10 May 2021 11:02:48 +0100 Subject: [PATCH 37/66] add doc for IntegerLiteral.getValue --- ql/src/codeql_ruby/ast/Literal.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/ql/src/codeql_ruby/ast/Literal.qll b/ql/src/codeql_ruby/ast/Literal.qll index fbf06f0e8cb..6a6cfc9ab5c 100644 --- a/ql/src/codeql_ruby/ast/Literal.qll +++ b/ql/src/codeql_ruby/ast/Literal.qll @@ -47,6 +47,7 @@ class IntegerLiteral extends NumericLiteral, TIntegerLiteral { final override string getValueText() { result = g.getValue() } + /** Gets the numerical value of this integer literal. */ final int getValue() { exists(string s, string values, string str | s = this.getValueText().toLowerCase() and From 0f3168f29305c93996e3374abd068a72200b9238 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Mon, 10 May 2021 21:23:24 +0100 Subject: [PATCH 38/66] record more parse errors --- extractor/src/extractor.rs | 102 ++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 35 deletions(-) diff --git a/extractor/src/extractor.rs b/extractor/src/extractor.rs index 83948ec887e..252d3e5f909 100644 --- a/extractor/src/extractor.rs +++ b/extractor/src/extractor.rs @@ -269,10 +269,8 @@ struct Visitor<'a> { } impl Visitor<'_> { - fn record_error( + fn record_parse_error( &mut self, - severity: usize, - error_tag: String, error_message: String, full_error_message: String, loc: Label, @@ -283,8 +281,8 @@ impl Visitor<'_> { "diagnostics", vec![ Arg::Label(id), - Arg::Int(severity), - Arg::String(error_tag), + Arg::Int(4), + Arg::String("parse_error".to_string()), Arg::String(error_message), Arg::String(full_error_message), Arg::Label(loc), @@ -292,7 +290,7 @@ impl Visitor<'_> { ); } - fn record_parse_error(&mut self, node: Node) { + fn record_enter_parse_error(&mut self, node: Node) { let error_message = if node.is_missing() { format!("parse error: expecting '{}'", node.kind()) } else { @@ -313,18 +311,12 @@ impl Visitor<'_> { end_line, end_column, ); - self.record_error( - 4, - "parse_error".to_string(), - error_message, - full_error_message, - loc, - ); + self.record_parse_error(error_message, full_error_message, loc); } fn enter_node(&mut self, node: Node) -> bool { if node.is_error() || node.is_missing() { - self.record_parse_error(node); + self.record_enter_parse_error(node); return false; } @@ -416,13 +408,7 @@ impl Visitor<'_> { node.start_position().row + 1, error_message ); - self.record_error( - 4, - "parse_error".to_string(), - error_message, - full_error_message, - loc, - ); + self.record_parse_error(error_message, full_error_message, loc); valid = false; } @@ -469,26 +455,56 @@ impl Visitor<'_> { values.push(Arg::Label(child_node.label)); } } else if field.name.is_some() { - error!( - "{}:{}: type mismatch for field {}::{} with type {:?} != {:?}", - &self.path, - node.start_position().row + 1, + let error_message = format!( + "type mismatch for field {}::{} with type {:?} != {:?}", node.kind(), child_node.field_name.unwrap_or("child"), child_node.type_name, field.type_info - ) + ); + let full_error_message = format!( + "{}:{}: {}", + &self.path, + node.start_position().row + 1, + error_message + ); + let (start_line, start_column, end_line, end_column) = + location_for(&self.source, *node); + let loc = self.trap_writer.location( + self.file_label, + start_line, + start_column, + end_line, + end_column, + ); + + self.record_parse_error(error_message, full_error_message, loc); } } else { if child_node.field_name.is_some() || child_node.type_name.named { - error!( - "{}:{}: value for unknown field: {}::{} and type {:?}", - &self.path, - node.start_position().row + 1, + let error_message = format!( + "value for unknown field: {}::{} and type {:?}", node.kind(), &child_node.field_name.unwrap_or("child"), &child_node.type_name ); + let full_error_message = format!( + "{}:{}: {}", + &self.path, + node.start_position().row + 1, + error_message + ); + let (start_line, start_column, end_line, end_column) = + location_for(&self.source, *node); + let loc = self.trap_writer.location( + self.file_label, + start_line, + start_column, + end_line, + end_column, + ); + + self.record_parse_error(error_message, full_error_message, loc); } } } @@ -502,10 +518,8 @@ impl Visitor<'_> { args.push(child_values.first().unwrap().clone()); } else { is_valid = false; - error!( - "{}:{}: {} for field: {}::{}", - &self.path, - node.start_position().row + 1, + let error_message = format!( + "{} for field: {}::{}", if child_values.is_empty() { "missing value" } else { @@ -513,7 +527,25 @@ impl Visitor<'_> { }, node.kind(), column_name - ) + ); + let full_error_message = format!( + "{}:{}: {}", + &self.path, + node.start_position().row + 1, + error_message + ); + + let (start_line, start_column, end_line, end_column) = + location_for(&self.source, *node); + let loc = self.trap_writer.location( + self.file_label, + start_line, + start_column, + end_line, + end_column, + ); + + self.record_parse_error(error_message, full_error_message, loc); } } Storage::Table { From 8ab95324eb3bb3b0e7d7401436fcfa23471e234b Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 11 May 2021 14:09:10 +0100 Subject: [PATCH 39/66] dedupe some error reporting code --- extractor/src/extractor.rs | 69 ++++++++++++-------------------------- 1 file changed, 21 insertions(+), 48 deletions(-) diff --git a/extractor/src/extractor.rs b/extractor/src/extractor.rs index 252d3e5f909..0383400ddc6 100644 --- a/extractor/src/extractor.rs +++ b/extractor/src/extractor.rs @@ -290,19 +290,12 @@ impl Visitor<'_> { ); } - fn record_enter_parse_error(&mut self, node: Node) { - let error_message = if node.is_missing() { - format!("parse error: expecting '{}'", node.kind()) - } else { - "parse error".to_string() - }; - let full_error_message = format!( - "{}:{}: {}", - &self.path, - node.start_position().row + 1, - error_message - ); - + fn record_parse_error_for_node( + &mut self, + error_message: String, + full_error_message: String, + node: Node, + ) { let (start_line, start_column, end_line, end_column) = location_for(&self.source, node); let loc = self.trap_writer.location( self.file_label, @@ -316,7 +309,18 @@ impl Visitor<'_> { fn enter_node(&mut self, node: Node) -> bool { if node.is_error() || node.is_missing() { - self.record_enter_parse_error(node); + let error_message = if node.is_missing() { + format!("parse error: expecting '{}'", node.kind()) + } else { + "parse error".to_string() + }; + let full_error_message = format!( + "{}:{}: {}", + &self.path, + node.start_position().row + 1, + error_message + ); + self.record_parse_error_for_node(error_message, full_error_message, node); return false; } @@ -468,17 +472,7 @@ impl Visitor<'_> { node.start_position().row + 1, error_message ); - let (start_line, start_column, end_line, end_column) = - location_for(&self.source, *node); - let loc = self.trap_writer.location( - self.file_label, - start_line, - start_column, - end_line, - end_column, - ); - - self.record_parse_error(error_message, full_error_message, loc); + self.record_parse_error_for_node(error_message, full_error_message, *node); } } else { if child_node.field_name.is_some() || child_node.type_name.named { @@ -494,17 +488,7 @@ impl Visitor<'_> { node.start_position().row + 1, error_message ); - let (start_line, start_column, end_line, end_column) = - location_for(&self.source, *node); - let loc = self.trap_writer.location( - self.file_label, - start_line, - start_column, - end_line, - end_column, - ); - - self.record_parse_error(error_message, full_error_message, loc); + self.record_parse_error_for_node(error_message, full_error_message, *node); } } } @@ -534,18 +518,7 @@ impl Visitor<'_> { node.start_position().row + 1, error_message ); - - let (start_line, start_column, end_line, end_column) = - location_for(&self.source, *node); - let loc = self.trap_writer.location( - self.file_label, - start_line, - start_column, - end_line, - end_column, - ); - - self.record_parse_error(error_message, full_error_message, loc); + self.record_parse_error_for_node(error_message, full_error_message, *node); } } Storage::Table { From de497dd1ba08c831631df279a68a67b8cc34f853 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 11 May 2021 17:19:28 +0100 Subject: [PATCH 40/66] tests for NumberOfFiles* summary queries --- .../NumberOfFilesExtractedSuccessfully.expected | 1 + .../diagnostics/NumberOfFilesExtractedSuccessfully.qlref | 1 + .../NumberOfFilesExtractedWithErrors.expected | 1 + .../diagnostics/NumberOfFilesExtractedWithErrors.qlref | 1 + ql/test/query-tests/diagnostics/src/foo.rb | 9 +++++++++ ql/test/query-tests/diagnostics/src/not_ruby.rb | 5 +++++ ql/test/query-tests/diagnostics/src/vendor/cache/lib.rb | 9 +++++++++ 7 files changed, 27 insertions(+) create mode 100644 ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.expected create mode 100644 ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.qlref create mode 100644 ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.expected create mode 100644 ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.qlref create mode 100644 ql/test/query-tests/diagnostics/src/foo.rb create mode 100755 ql/test/query-tests/diagnostics/src/not_ruby.rb create mode 100644 ql/test/query-tests/diagnostics/src/vendor/cache/lib.rb diff --git a/ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.expected b/ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.expected new file mode 100644 index 00000000000..a882f18620b --- /dev/null +++ b/ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.expected @@ -0,0 +1 @@ +| 2 | diff --git a/ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.qlref b/ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.qlref new file mode 100644 index 00000000000..78179fa14e4 --- /dev/null +++ b/ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.qlref @@ -0,0 +1 @@ +queries/summary/NumberOfFilesExtractedSuccessfully.ql \ No newline at end of file diff --git a/ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.expected b/ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.expected new file mode 100644 index 00000000000..2a4f078a25f --- /dev/null +++ b/ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.expected @@ -0,0 +1 @@ +| 1 | diff --git a/ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.qlref b/ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.qlref new file mode 100644 index 00000000000..17823cc8837 --- /dev/null +++ b/ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.qlref @@ -0,0 +1 @@ +queries/summary/NumberOfFilesExtractedWithErrors.ql \ No newline at end of file diff --git a/ql/test/query-tests/diagnostics/src/foo.rb b/ql/test/query-tests/diagnostics/src/foo.rb new file mode 100644 index 00000000000..7b831d230ed --- /dev/null +++ b/ql/test/query-tests/diagnostics/src/foo.rb @@ -0,0 +1,9 @@ +# comment + +def hello + p "hello world" +end + +# another one + +hello diff --git a/ql/test/query-tests/diagnostics/src/not_ruby.rb b/ql/test/query-tests/diagnostics/src/not_ruby.rb new file mode 100755 index 00000000000..51128f4f7fe --- /dev/null +++ b/ql/test/query-tests/diagnostics/src/not_ruby.rb @@ -0,0 +1,5 @@ +#!/bin/bash + +# This is a bash script +export FOO="$(whereis ls)" +exec "$FOO" "$(dirname "$0")" diff --git a/ql/test/query-tests/diagnostics/src/vendor/cache/lib.rb b/ql/test/query-tests/diagnostics/src/vendor/cache/lib.rb new file mode 100644 index 00000000000..f75db7941db --- /dev/null +++ b/ql/test/query-tests/diagnostics/src/vendor/cache/lib.rb @@ -0,0 +1,9 @@ +# comment + +def hello + p "hello lib" +end + +# another one + +hello From d1d8cff915185c32bd626218d640d932b684bedb Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 11 May 2021 19:10:17 +0100 Subject: [PATCH 41/66] tests for some more diagnostics queries --- .../query-tests/diagnostics/FilesExtractedSuccessfully.expected | 2 ++ .../query-tests/diagnostics/FilesExtractedSuccessfully.qlref | 1 + .../query-tests/diagnostics/FilesExtractedWithErrors.expected | 1 + ql/test/query-tests/diagnostics/FilesExtractedWithErrors.qlref | 1 + 4 files changed, 5 insertions(+) create mode 100644 ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.expected create mode 100644 ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.qlref create mode 100644 ql/test/query-tests/diagnostics/FilesExtractedWithErrors.expected create mode 100644 ql/test/query-tests/diagnostics/FilesExtractedWithErrors.qlref diff --git a/ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.expected b/ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.expected new file mode 100644 index 00000000000..4a67220f95d --- /dev/null +++ b/ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.expected @@ -0,0 +1,2 @@ +| src/foo.rb:0:0:0:0 | src/foo.rb | | +| src/vendor/cache/lib.rb:0:0:0:0 | src/vendor/cache/lib.rb | | diff --git a/ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.qlref b/ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.qlref new file mode 100644 index 00000000000..e3c75791990 --- /dev/null +++ b/ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.qlref @@ -0,0 +1 @@ +queries/diagnostics/FilesExtractedSuccessfully.ql \ No newline at end of file diff --git a/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.expected b/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.expected new file mode 100644 index 00000000000..4de5e7ac0fc --- /dev/null +++ b/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.expected @@ -0,0 +1 @@ +| src/not_ruby.rb:0:0:0:0 | src/not_ruby.rb | | diff --git a/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.qlref b/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.qlref new file mode 100644 index 00000000000..c98756d23a7 --- /dev/null +++ b/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.qlref @@ -0,0 +1 @@ +queries/diagnostics/FilesExtractedWithErrors.ql \ No newline at end of file From 9663b74e12931bb1eedf0ac61f0d82c445865efe Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 11 May 2021 19:16:45 +0100 Subject: [PATCH 42/66] use severity level 3 to indicate an extraction error for a file --- extractor/src/extractor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extractor/src/extractor.rs b/extractor/src/extractor.rs index 0383400ddc6..b5ba70ae554 100644 --- a/extractor/src/extractor.rs +++ b/extractor/src/extractor.rs @@ -281,7 +281,7 @@ impl Visitor<'_> { "diagnostics", vec![ Arg::Label(id), - Arg::Int(4), + Arg::Int(3), Arg::String("parse_error".to_string()), Arg::String(error_message), Arg::String(full_error_message), From 1381d8d076109bb1558a63e51879cbe12cb87884 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 11 May 2021 19:28:31 +0100 Subject: [PATCH 43/66] tidy up Diagnostics library --- ql/src/codeql_ruby/Diagnostics.qll | 38 ++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/ql/src/codeql_ruby/Diagnostics.qll b/ql/src/codeql_ruby/Diagnostics.qll index 4e35a9a5dd1..e2e28a84b07 100644 --- a/ql/src/codeql_ruby/Diagnostics.qll +++ b/ql/src/codeql_ruby/Diagnostics.qll @@ -2,30 +2,54 @@ private import codeql.Locations /** A diagnostic emitted during extraction, such as a parse error */ class Diagnostic extends @diagnostic { + int severity; + string tag; + string message; + string fullMessage; + Location location; + + Diagnostic() { diagnostics(this, severity, tag, message, fullMessage, location) } + /** * Gets the numerical severity level associated with this diagnostic. */ - int getSeverity() { diagnostics(this, result, _, _, _, _) } + int getSeverity() { result = severity } + + /** Gets a string representation of the severity of this diagnostic. */ + string getSeverityText() { + severity = 0 and result = "Hidden" + or + severity = 1 and result = "Info" + or + severity = 2 and result = "Warning" + or + severity = 3 and result = "Error" + } /** Gets the error code associated with this diagnostic, e.g. parse_error. */ - string getTag() { diagnostics(this, _, result, _, _, _) } + string getTag() { result = tag } /** * Gets the error message text associated with this diagnostic. */ - string getMessage() { diagnostics(this, _, _, result, _, _) } + string getMessage() { result = message } /** * Gets the full error message text associated with this diagnostic. */ - string getFullMessage() { diagnostics(this, _, _, _, result, _) } + string getFullMessage() { result = fullMessage } /** Gets the source location of this diagnostic. */ - Location getLocation() { diagnostics(this, _, _, _, _, result) } + Location getLocation() { result = location } + /** Gets a textual representation of this diagnostic. */ string toString() { result = this.getMessage() } } +/** A diagnostic relating to a particular error in extracting a file. */ class ExtractionError extends Diagnostic { - ExtractionError() { this.getTag() = "parse_error" } -} \ No newline at end of file + ExtractionError() { + this.getSeverity() = 3 and + this.getTag() = "parse_error" + } +} From 9b115129fe0eccde726ef0de953dccd1fb6c6f72 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 11 May 2021 19:34:10 +0100 Subject: [PATCH 44/66] move diagnostics queries to match other languages more closely --- ql/src/queries/diagnostics/ExtractionErrors.ql | 18 ++++++++++++++++++ .../diagnostics/FilesExtractedWithErrors.ql | 14 -------------- .../diagnostics/SuccessfullyExtractedFiles.ql | 8 +++++--- ...l => NumberOfSuccessfullyExtractedFiles.ql} | 0 4 files changed, 23 insertions(+), 17 deletions(-) create mode 100644 ql/src/queries/diagnostics/ExtractionErrors.ql delete mode 100644 ql/src/queries/diagnostics/FilesExtractedWithErrors.ql rename ql/src/queries/summary/{NumberOfSuccesfullyExtractedFiles.ql => NumberOfSuccessfullyExtractedFiles.ql} (100%) diff --git a/ql/src/queries/diagnostics/ExtractionErrors.ql b/ql/src/queries/diagnostics/ExtractionErrors.ql new file mode 100644 index 00000000000..224f0d23c47 --- /dev/null +++ b/ql/src/queries/diagnostics/ExtractionErrors.ql @@ -0,0 +1,18 @@ +/** + * @name Extraction errors + * @description List all extraction errors for files in the source code directory. + * @kind diagnostic + * @id rb/diagnostics/extraction-errors + */ + +import ruby +import codeql_ruby.Diagnostics + +/** Gets the SARIF severity to associate an error. */ +int getSeverity() { result = 2 } + +from ExtractionError error, File f +where + f = error.getLocation().getFile() and + exists(f.getRelativePath()) +select error, "Extraction failed in " + f + " with error " + error.getMessage(), getSeverity() diff --git a/ql/src/queries/diagnostics/FilesExtractedWithErrors.ql b/ql/src/queries/diagnostics/FilesExtractedWithErrors.ql deleted file mode 100644 index 8db409eefd1..00000000000 --- a/ql/src/queries/diagnostics/FilesExtractedWithErrors.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Files extracted with errors - * @description Lists files that were extracted, but may be incomplete due to - * extraction errors. - * @kind diagnostic - * @id rb/diagnostics/files-extracted-with-errors - */ - -import ruby -import codeql_ruby.Diagnostics - -from File f -where exists(ExtractionError e | e.getLocation().getFile() = f) -select f, "" diff --git a/ql/src/queries/diagnostics/SuccessfullyExtractedFiles.ql b/ql/src/queries/diagnostics/SuccessfullyExtractedFiles.ql index f7c3bbd14af..3bc58c3467d 100644 --- a/ql/src/queries/diagnostics/SuccessfullyExtractedFiles.ql +++ b/ql/src/queries/diagnostics/SuccessfullyExtractedFiles.ql @@ -1,7 +1,7 @@ /** * @name Successfully extracted files - * @description Lists all files that were extracted without encountering an - * error in the file. + * @description Lists all files in the source code directory that were extracted + * without encountering an error in the file. * @kind diagnostic * @id rb/diagnostics/successfully-extracted-files */ @@ -10,5 +10,7 @@ import ruby import codeql_ruby.Diagnostics from File f -where not exists(ExtractionError e | e.getLocation().getFile() = f) +where + not exists(ExtractionError e | e.getLocation().getFile() = f) and + exists(f.getRelativePath()) select f, "" diff --git a/ql/src/queries/summary/NumberOfSuccesfullyExtractedFiles.ql b/ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql similarity index 100% rename from ql/src/queries/summary/NumberOfSuccesfullyExtractedFiles.ql rename to ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql From 49d9bb798c8b9f6fddb1c47dcee514954431b782 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 11 May 2021 19:52:52 +0100 Subject: [PATCH 45/66] revamp the diagnostics tests --- .../diagnostics/ExtractionErrors.expected | 5 +++++ .../diagnostics/ExtractionErrors.qlref | 1 + .../FilesExtractedSuccessfully.qlref | 1 - .../FilesExtractedWithErrors.expected | 1 - .../diagnostics/FilesExtractedWithErrors.qlref | 1 - .../NumberOfFilesExtractedSuccessfully.qlref | 1 - .../NumberOfFilesExtractedWithErrors.expected | 2 +- ...NumberOfSuccessfullyExtractedFiles.expected} | 0 .../NumberOfSuccessfullyExtractedFiles.qlref | 1 + ...cted => SuccessfullyExtractedFiles.expected} | 0 .../SuccessfullyExtractedFiles.qlref | 1 + .../diagnostics/src/unsupported_feature.rb | 17 +++++++++++++++++ 12 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 ql/test/query-tests/diagnostics/ExtractionErrors.expected create mode 100644 ql/test/query-tests/diagnostics/ExtractionErrors.qlref delete mode 100644 ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.qlref delete mode 100644 ql/test/query-tests/diagnostics/FilesExtractedWithErrors.expected delete mode 100644 ql/test/query-tests/diagnostics/FilesExtractedWithErrors.qlref delete mode 100644 ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.qlref rename ql/test/query-tests/diagnostics/{NumberOfFilesExtractedSuccessfully.expected => NumberOfSuccessfullyExtractedFiles.expected} (100%) create mode 100644 ql/test/query-tests/diagnostics/NumberOfSuccessfullyExtractedFiles.qlref rename ql/test/query-tests/diagnostics/{FilesExtractedSuccessfully.expected => SuccessfullyExtractedFiles.expected} (100%) create mode 100644 ql/test/query-tests/diagnostics/SuccessfullyExtractedFiles.qlref create mode 100644 ql/test/query-tests/diagnostics/src/unsupported_feature.rb diff --git a/ql/test/query-tests/diagnostics/ExtractionErrors.expected b/ql/test/query-tests/diagnostics/ExtractionErrors.expected new file mode 100644 index 00000000000..22431857197 --- /dev/null +++ b/ql/test/query-tests/diagnostics/ExtractionErrors.expected @@ -0,0 +1,5 @@ +| src/not_ruby.rb:5:25:5:26 | parse error | Extraction failed in src/not_ruby.rb with error parse error | 2 | +| src/unsupported_feature.rb:2:18:2:20 | parse error | Extraction failed in src/unsupported_feature.rb with error parse error | 2 | +| src/unsupported_feature.rb:3:13:3:15 | parse error | Extraction failed in src/unsupported_feature.rb with error parse error | 2 | +| src/unsupported_feature.rb:6:15:6:17 | parse error | Extraction failed in src/unsupported_feature.rb with error parse error | 2 | +| src/unsupported_feature.rb:7:20:7:22 | parse error | Extraction failed in src/unsupported_feature.rb with error parse error | 2 | diff --git a/ql/test/query-tests/diagnostics/ExtractionErrors.qlref b/ql/test/query-tests/diagnostics/ExtractionErrors.qlref new file mode 100644 index 00000000000..ffbdb0a7b1b --- /dev/null +++ b/ql/test/query-tests/diagnostics/ExtractionErrors.qlref @@ -0,0 +1 @@ +queries/diagnostics/ExtractionErrors.ql \ No newline at end of file diff --git a/ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.qlref b/ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.qlref deleted file mode 100644 index e3c75791990..00000000000 --- a/ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.qlref +++ /dev/null @@ -1 +0,0 @@ -queries/diagnostics/FilesExtractedSuccessfully.ql \ No newline at end of file diff --git a/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.expected b/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.expected deleted file mode 100644 index 4de5e7ac0fc..00000000000 --- a/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.expected +++ /dev/null @@ -1 +0,0 @@ -| src/not_ruby.rb:0:0:0:0 | src/not_ruby.rb | | diff --git a/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.qlref b/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.qlref deleted file mode 100644 index c98756d23a7..00000000000 --- a/ql/test/query-tests/diagnostics/FilesExtractedWithErrors.qlref +++ /dev/null @@ -1 +0,0 @@ -queries/diagnostics/FilesExtractedWithErrors.ql \ No newline at end of file diff --git a/ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.qlref b/ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.qlref deleted file mode 100644 index 78179fa14e4..00000000000 --- a/ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.qlref +++ /dev/null @@ -1 +0,0 @@ -queries/summary/NumberOfFilesExtractedSuccessfully.ql \ No newline at end of file diff --git a/ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.expected b/ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.expected index 2a4f078a25f..a882f18620b 100644 --- a/ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.expected +++ b/ql/test/query-tests/diagnostics/NumberOfFilesExtractedWithErrors.expected @@ -1 +1 @@ -| 1 | +| 2 | diff --git a/ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.expected b/ql/test/query-tests/diagnostics/NumberOfSuccessfullyExtractedFiles.expected similarity index 100% rename from ql/test/query-tests/diagnostics/NumberOfFilesExtractedSuccessfully.expected rename to ql/test/query-tests/diagnostics/NumberOfSuccessfullyExtractedFiles.expected diff --git a/ql/test/query-tests/diagnostics/NumberOfSuccessfullyExtractedFiles.qlref b/ql/test/query-tests/diagnostics/NumberOfSuccessfullyExtractedFiles.qlref new file mode 100644 index 00000000000..5f6eda05206 --- /dev/null +++ b/ql/test/query-tests/diagnostics/NumberOfSuccessfullyExtractedFiles.qlref @@ -0,0 +1 @@ +queries/summary/NumberOfSuccessfullyExtractedFiles.ql \ No newline at end of file diff --git a/ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.expected b/ql/test/query-tests/diagnostics/SuccessfullyExtractedFiles.expected similarity index 100% rename from ql/test/query-tests/diagnostics/FilesExtractedSuccessfully.expected rename to ql/test/query-tests/diagnostics/SuccessfullyExtractedFiles.expected diff --git a/ql/test/query-tests/diagnostics/SuccessfullyExtractedFiles.qlref b/ql/test/query-tests/diagnostics/SuccessfullyExtractedFiles.qlref new file mode 100644 index 00000000000..6dc0952ba3a --- /dev/null +++ b/ql/test/query-tests/diagnostics/SuccessfullyExtractedFiles.qlref @@ -0,0 +1 @@ +queries/diagnostics/SuccessfullyExtractedFiles.ql \ No newline at end of file diff --git a/ql/test/query-tests/diagnostics/src/unsupported_feature.rb b/ql/test/query-tests/diagnostics/src/unsupported_feature.rb new file mode 100644 index 00000000000..c5a39a3619d --- /dev/null +++ b/ql/test/query-tests/diagnostics/src/unsupported_feature.rb @@ -0,0 +1,17 @@ +class Foo + def initialize(...) + do_init(...) + end + + def do_init(...) + really_do_init(...) + end + + def really_do_init(bar, baz:, &block) + puts bar + puts baz + block.call + end +end + +Foo.new("hello", baz: "world") { || puts "!" } From 0016146e1105d26ac181a09609144f83837ef0aa Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 11 May 2021 21:07:08 +0100 Subject: [PATCH 46/66] limit summary queries to files from within the source directory --- ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql | 4 +++- ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql b/ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql index eb871a4086d..92ed5ca6684 100644 --- a/ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql +++ b/ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql @@ -10,4 +10,6 @@ import ruby import codeql_ruby.Diagnostics -select count(File f | exists(ExtractionError e | e.getLocation().getFile() = f)) +select count(File f | + exists(ExtractionError e | e.getLocation().getFile() = f) and exists(f.getRelativePath()) + ) diff --git a/ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql b/ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql index 36a584e2271..95049f9ef3c 100644 --- a/ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql +++ b/ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql @@ -10,4 +10,6 @@ import ruby import codeql_ruby.Diagnostics -select count(File f | not exists(ExtractionError e | e.getLocation().getFile() = f)) +select count(File f | + not exists(ExtractionError e | e.getLocation().getFile() = f) and exists(f.getRelativePath()) + ) From ea1c7b51efc143be93e9e7d4420590022cc46af9 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 5 May 2021 20:34:08 +0200 Subject: [PATCH 47/66] Add more operator assignment tests --- ql/test/library-tests/ast/Ast.expected | 34 ++++ .../library-tests/ast/calls/calls.expected | 14 ++ ql/test/library-tests/ast/calls/calls.rb | 1 + .../ast/operations/assignment.expected | 12 ++ .../ast/operations/operation.expected | 12 ++ .../ast/operations/operations.rb | 13 +- .../controlflow/graph/Cfg.expected | 171 ++++++++++++++++++ .../controlflow/graph/desugar.rb | 22 +++ 8 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 ql/test/library-tests/controlflow/graph/desugar.rb diff --git a/ql/test/library-tests/ast/Ast.expected b/ql/test/library-tests/ast/Ast.expected index 7f5e877af1c..ff9b6cb5dae 100644 --- a/ql/test/library-tests/ast/Ast.expected +++ b/ql/test/library-tests/ast/Ast.expected @@ -567,6 +567,21 @@ calls/calls.rb: # 319| getReceiver: [Self] self # 319| getArgument: [IntegerLiteral] 0 # 319| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 320| getStmt: [AssignMulExpr] ... *= ... +# 320| getAnOperand/getLeftOperand: [ElementReference, SetterMethodCall] ...[...] +# 320| getReceiver: [MethodCall] call to bar +# 320| getReceiver: [MethodCall] call to foo +# 320| getReceiver: [Self] self +# 320| getArgument: [IntegerLiteral] 0 +# 320| getArgument: [MethodCall] call to baz +# 320| getReceiver: [MethodCall] call to foo +# 320| getReceiver: [Self] self +# 320| getArgument: [AddExpr] ... + ... +# 320| getAnOperand/getLeftOperand: [MethodCall] call to boo +# 320| getReceiver: [MethodCall] call to foo +# 320| getReceiver: [Self] self +# 320| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 320| getAnOperand/getRightOperand: [IntegerLiteral] 2 control/cases.rb: # 1| [Toplevel] cases.rb # 2| getStmt: [AssignExpr] ... = ... @@ -1718,6 +1733,25 @@ operations/operations.rb: # 84| getStmt: [AssignBitwiseXorExpr] ... ^= ... # 84| getAnOperand/getLeftOperand: [LocalVariableAccess] baz # 84| getAnOperand/getRightOperand: [LocalVariableAccess] qux +# 86| getStmt: [ClassDeclaration] X +# 87| getStmt: [AssignExpr] ... = ... +# 87| getAnOperand/getLeftOperand: [InstanceVariableAccess] @x +# 87| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 88| getStmt: [AssignAddExpr] ... += ... +# 88| getAnOperand/getLeftOperand: [InstanceVariableAccess] @x +# 88| getAnOperand/getRightOperand: [IntegerLiteral] 2 +# 90| getStmt: [AssignExpr] ... = ... +# 90| getAnOperand/getLeftOperand: [ClassVariableAccess] @@y +# 90| getAnOperand/getRightOperand: [IntegerLiteral] 3 +# 91| getStmt: [AssignDivExpr] ... /= ... +# 91| getAnOperand/getLeftOperand: [ClassVariableAccess] @@y +# 91| getAnOperand/getRightOperand: [IntegerLiteral] 4 +# 94| getStmt: [AssignExpr] ... = ... +# 94| getAnOperand/getLeftOperand: [GlobalVariableAccess] $global_var +# 94| getAnOperand/getRightOperand: [IntegerLiteral] 5 +# 95| getStmt: [AssignMulExpr] ... *= ... +# 95| getAnOperand/getLeftOperand: [GlobalVariableAccess] $global_var +# 95| getAnOperand/getRightOperand: [IntegerLiteral] 6 params/params.rb: # 1| [Toplevel] params.rb # 4| getStmt: [Method] identifier_method_params diff --git a/ql/test/library-tests/ast/calls/calls.expected b/ql/test/library-tests/ast/calls/calls.expected index 74bcfee07ed..e10de4ae3d5 100644 --- a/ql/test/library-tests/ast/calls/calls.expected +++ b/ql/test/library-tests/ast/calls/calls.expected @@ -36,6 +36,12 @@ callsWithArguments | calls.rb:317:5:317:10 | ...[...] | []= | 0 | calls.rb:317:9:317:9 | 5 | | calls.rb:319:1:319:6 | ...[...] | [] | 0 | calls.rb:319:5:319:5 | 0 | | calls.rb:319:1:319:6 | ...[...] | []= | 0 | calls.rb:319:5:319:5 | 0 | +| calls.rb:320:1:320:32 | ...[...] | [] | 0 | calls.rb:320:9:320:9 | 0 | +| calls.rb:320:1:320:32 | ...[...] | [] | 1 | calls.rb:320:12:320:18 | call to baz | +| calls.rb:320:1:320:32 | ...[...] | [] | 2 | calls.rb:320:21:320:31 | ... + ... | +| calls.rb:320:1:320:32 | ...[...] | []= | 0 | calls.rb:320:9:320:9 | 0 | +| calls.rb:320:1:320:32 | ...[...] | []= | 1 | calls.rb:320:12:320:18 | call to baz | +| calls.rb:320:1:320:32 | ...[...] | []= | 2 | calls.rb:320:21:320:31 | ... + ... | callsWithReceiver | calls.rb:2:1:2:5 | call to foo | calls.rb:2:1:2:5 | self | | calls.rb:5:1:5:10 | call to bar | calls.rb:5:1:5:3 | Foo | @@ -216,6 +222,13 @@ callsWithReceiver | calls.rb:318:1:318:10 | call to count/count= | calls.rb:318:1:318:4 | self | | calls.rb:319:1:319:3 | call to foo | calls.rb:319:1:319:3 | self | | calls.rb:319:1:319:6 | ...[...] | calls.rb:319:1:319:3 | call to foo | +| calls.rb:320:1:320:3 | call to foo | calls.rb:320:1:320:3 | self | +| calls.rb:320:1:320:7 | call to bar | calls.rb:320:1:320:3 | call to foo | +| calls.rb:320:1:320:32 | ...[...] | calls.rb:320:1:320:7 | call to bar | +| calls.rb:320:12:320:14 | call to foo | calls.rb:320:12:320:14 | self | +| calls.rb:320:12:320:18 | call to baz | calls.rb:320:12:320:14 | call to foo | +| calls.rb:320:21:320:23 | call to foo | calls.rb:320:21:320:23 | self | +| calls.rb:320:21:320:27 | call to boo | calls.rb:320:21:320:23 | call to foo | callsWithBlock | calls.rb:17:1:17:17 | call to foo | calls.rb:17:5:17:17 | { ... } | | calls.rb:20:1:22:3 | call to foo | calls.rb:20:5:22:3 | do ... end | @@ -262,3 +275,4 @@ setterCalls | calls.rb:317:5:317:10 | ...[...] | | calls.rb:318:1:318:10 | call to count/count= | | calls.rb:319:1:319:6 | ...[...] | +| calls.rb:320:1:320:32 | ...[...] | diff --git a/ql/test/library-tests/ast/calls/calls.rb b/ql/test/library-tests/ast/calls/calls.rb index 8b827d07f9b..1362b043e8a 100644 --- a/ql/test/library-tests/ast/calls/calls.rb +++ b/ql/test/library-tests/ast/calls/calls.rb @@ -317,3 +317,4 @@ self.foo, *self.bar, foo[4] = [1, 2, 3, 4] a, *foo[5] = [1, 2, 3] self.count += 1 foo[0] += 1 +foo.bar[0, foo.baz, foo.boo + 1] *= 2 diff --git a/ql/test/library-tests/ast/operations/assignment.expected b/ql/test/library-tests/ast/operations/assignment.expected index d1f34896b31..454f86743ba 100644 --- a/ql/test/library-tests/ast/operations/assignment.expected +++ b/ql/test/library-tests/ast/operations/assignment.expected @@ -30,6 +30,12 @@ assignments | operations.rb:82:2:82:12 | ... &= ... | &= | operations.rb:82:2:82:4 | foo | operations.rb:82:9:82:12 | mask | AssignBitwiseAndExpr | | operations.rb:83:2:83:12 | ... \|= ... | \|= | operations.rb:83:2:83:4 | bar | operations.rb:83:9:83:12 | 0x01 | AssignBitwiseOrExpr | | operations.rb:84:2:84:11 | ... ^= ... | ^= | operations.rb:84:2:84:4 | baz | operations.rb:84:9:84:11 | qux | AssignBitwiseXorExpr | +| operations.rb:87:3:87:8 | ... = ... | = | operations.rb:87:3:87:4 | @x | operations.rb:87:8:87:8 | 1 | AssignExpr | +| operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:3:88:4 | @x | operations.rb:88:9:88:9 | 2 | AssignAddExpr | +| operations.rb:90:3:90:9 | ... = ... | = | operations.rb:90:3:90:5 | @@y | operations.rb:90:9:90:9 | 3 | AssignExpr | +| operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:3:91:5 | @@y | operations.rb:91:10:91:10 | 4 | AssignDivExpr | +| operations.rb:94:1:94:15 | ... = ... | = | operations.rb:94:1:94:11 | $global_var | operations.rb:94:15:94:15 | 5 | AssignExpr | +| operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:1:95:11 | $global_var | operations.rb:95:16:95:16 | 6 | AssignMulExpr | assignOperations | operations.rb:68:1:68:8 | ... += ... | += | operations.rb:68:1:68:1 | x | operations.rb:68:6:68:8 | 128 | AssignAddExpr | | operations.rb:69:1:69:7 | ... -= ... | -= | operations.rb:69:1:69:1 | y | operations.rb:69:6:69:7 | 32 | AssignSubExpr | @@ -44,6 +50,9 @@ assignOperations | operations.rb:82:2:82:12 | ... &= ... | &= | operations.rb:82:2:82:4 | foo | operations.rb:82:9:82:12 | mask | AssignBitwiseAndExpr | | operations.rb:83:2:83:12 | ... \|= ... | \|= | operations.rb:83:2:83:4 | bar | operations.rb:83:9:83:12 | 0x01 | AssignBitwiseOrExpr | | operations.rb:84:2:84:11 | ... ^= ... | ^= | operations.rb:84:2:84:4 | baz | operations.rb:84:9:84:11 | qux | AssignBitwiseXorExpr | +| operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:3:88:4 | @x | operations.rb:88:9:88:9 | 2 | AssignAddExpr | +| operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:3:91:5 | @@y | operations.rb:91:10:91:10 | 4 | AssignDivExpr | +| operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:1:95:11 | $global_var | operations.rb:95:16:95:16 | 6 | AssignMulExpr | assignArithmeticOperations | operations.rb:68:1:68:8 | ... += ... | += | operations.rb:68:1:68:1 | x | operations.rb:68:6:68:8 | 128 | AssignAddExpr | | operations.rb:69:1:69:7 | ... -= ... | -= | operations.rb:69:1:69:1 | y | operations.rb:69:6:69:7 | 32 | AssignSubExpr | @@ -51,6 +60,9 @@ assignArithmeticOperations | operations.rb:71:1:71:6 | ... /= ... | /= | operations.rb:71:1:71:1 | b | operations.rb:71:6:71:6 | 4 | AssignDivExpr | | operations.rb:72:1:72:6 | ... %= ... | %= | operations.rb:72:1:72:1 | z | operations.rb:72:6:72:6 | 2 | AssignModuloExpr | | operations.rb:73:1:73:11 | ... **= ... | **= | operations.rb:73:1:73:3 | foo | operations.rb:73:9:73:11 | bar | AssignExponentExpr | +| operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:3:88:4 | @x | operations.rb:88:9:88:9 | 2 | AssignAddExpr | +| operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:3:91:5 | @@y | operations.rb:91:10:91:10 | 4 | AssignDivExpr | +| operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:1:95:11 | $global_var | operations.rb:95:16:95:16 | 6 | AssignMulExpr | assignLogicalOperations | operations.rb:76:2:76:8 | ... &&= ... | &&= | operations.rb:76:2:76:2 | x | operations.rb:76:8:76:8 | y | AssignLogicalAndExpr | | operations.rb:77:2:77:8 | ... \|\|= ... | \|\|= | operations.rb:77:2:77:2 | a | operations.rb:77:8:77:8 | b | AssignLogicalOrExpr | diff --git a/ql/test/library-tests/ast/operations/operation.expected b/ql/test/library-tests/ast/operations/operation.expected index 3d5346e6346..7f4d25068eb 100644 --- a/ql/test/library-tests/ast/operations/operation.expected +++ b/ql/test/library-tests/ast/operations/operation.expected @@ -116,3 +116,15 @@ | operations.rb:83:2:83:12 | ... \|= ... | \|= | operations.rb:83:9:83:12 | 0x01 | AssignBitwiseOrExpr | | operations.rb:84:2:84:11 | ... ^= ... | ^= | operations.rb:84:2:84:4 | baz | AssignBitwiseXorExpr | | operations.rb:84:2:84:11 | ... ^= ... | ^= | operations.rb:84:9:84:11 | qux | AssignBitwiseXorExpr | +| operations.rb:87:3:87:8 | ... = ... | = | operations.rb:87:3:87:4 | @x | AssignExpr | +| operations.rb:87:3:87:8 | ... = ... | = | operations.rb:87:8:87:8 | 1 | AssignExpr | +| operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:3:88:4 | @x | AssignAddExpr | +| operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:9:88:9 | 2 | AssignAddExpr | +| operations.rb:90:3:90:9 | ... = ... | = | operations.rb:90:3:90:5 | @@y | AssignExpr | +| operations.rb:90:3:90:9 | ... = ... | = | operations.rb:90:9:90:9 | 3 | AssignExpr | +| operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:3:91:5 | @@y | AssignDivExpr | +| operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:10:91:10 | 4 | AssignDivExpr | +| operations.rb:94:1:94:15 | ... = ... | = | operations.rb:94:1:94:11 | $global_var | AssignExpr | +| operations.rb:94:1:94:15 | ... = ... | = | operations.rb:94:15:94:15 | 5 | AssignExpr | +| operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:1:95:11 | $global_var | AssignMulExpr | +| operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:16:95:16 | 6 | AssignMulExpr | diff --git a/ql/test/library-tests/ast/operations/operations.rb b/ql/test/library-tests/ast/operations/operations.rb index 707a2d36425..effee5860ba 100644 --- a/ql/test/library-tests/ast/operations/operations.rb +++ b/ql/test/library-tests/ast/operations/operations.rb @@ -81,4 +81,15 @@ foo **= bar y >>= 3 foo &= mask bar |= 0x01 - baz ^= qux \ No newline at end of file + baz ^= qux + +class X + @x = 1 + @x += 2 + + @@y = 3 + @@y /= 4 +end + +$global_var = 5 +$global_var *= 6 diff --git a/ql/test/library-tests/controlflow/graph/Cfg.expected b/ql/test/library-tests/controlflow/graph/Cfg.expected index 3e39856c559..84e66808854 100644 --- a/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -2083,6 +2083,177 @@ cfg.rb: # 194| x #-----| -> call to puts +desugar.rb: +# 1| enter m1 +#-----| -> x + +# 1| enter desugar.rb +#-----| -> m1 + +# 1| m1 +#-----| -> m2 + +# 1| exit m1 + +# 1| exit desugar.rb + +# 1| exit m1 (normal) +#-----| -> exit m1 + +# 1| exit desugar.rb (normal) +#-----| -> exit desugar.rb + +# 1| x +#-----| -> x + +# 2| ... += ... +#-----| -> exit m1 (normal) + +# 2| x +#-----| -> 1 + +# 2| 1 +#-----| -> ... += ... + +# 5| enter m2 +#-----| -> x + +# 5| m2 +#-----| -> m3 + +# 5| exit m2 + +# 5| exit m2 (normal) +#-----| -> exit m2 + +# 5| x +#-----| -> x + +# 6| ... += ... +#-----| -> exit m2 (normal) + +# 6| call to count/count= +#-----| -> 1 + +# 6| call to foo +#-----| -> call to count/count= + +# 6| x +#-----| -> call to foo + +# 6| 1 +#-----| -> ... += ... + +# 9| enter m3 +#-----| -> x + +# 9| m3 +#-----| -> X + +# 9| exit m3 + +# 9| exit m3 (normal) +#-----| -> exit m3 + +# 9| x +#-----| -> y + +# 9| y +#-----| -> x + +# 10| ... += ... +#-----| -> exit m3 (normal) + +# 10| ...[...] +#-----| -> 1 + +# 10| call to foo +#-----| -> 0 + +# 10| x +#-----| -> call to foo + +# 10| 0 +#-----| -> y + +# 10| call to bar +#-----| -> x + +# 10| y +#-----| -> call to bar + +# 10| ... + ... +#-----| -> ...[...] + +# 10| call to baz +#-----| -> 3 + +# 10| x +#-----| -> call to baz + +# 10| 3 +#-----| -> ... + ... + +# 10| 1 +#-----| -> ... += ... + +# 13| X +#-----| -> @x + +# 14| ... = ... +#-----| -> @x + +# 14| @x +#-----| -> 1 + +# 14| 1 +#-----| -> ... = ... + +# 15| ... += ... +#-----| -> @@y + +# 15| @x +#-----| -> 2 + +# 15| 2 +#-----| -> ... += ... + +# 17| ... = ... +#-----| -> @@y + +# 17| @@y +#-----| -> 3 + +# 17| 3 +#-----| -> ... = ... + +# 18| ... /= ... +#-----| -> $global_var + +# 18| @@y +#-----| -> 4 + +# 18| 4 +#-----| -> ... /= ... + +# 21| ... = ... +#-----| -> $global_var + +# 21| $global_var +#-----| -> 5 + +# 21| 5 +#-----| -> ... = ... + +# 22| ... *= ... +#-----| -> exit desugar.rb (normal) + +# 22| $global_var +#-----| -> 6 + +# 22| 6 +#-----| -> ... *= ... + exit.rb: # 1| enter m1 #-----| -> x diff --git a/ql/test/library-tests/controlflow/graph/desugar.rb b/ql/test/library-tests/controlflow/graph/desugar.rb new file mode 100644 index 00000000000..25dd0e48e0e --- /dev/null +++ b/ql/test/library-tests/controlflow/graph/desugar.rb @@ -0,0 +1,22 @@ +def m1 x + x += 1 +end + +def m2 x + x.foo.count += 1 +end + +def m3 x, y + x.foo[0, y.bar, x.baz + 3] += 1 +end + +class X + @x = 1 + @x += 2 + + @@y = 3 + @@y /= 4 +end + +$global_var = 5 +$global_var *= 6 From 0dad1a477920c034a17af012a649c7befd18aa9e Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 12 May 2021 16:38:37 +0100 Subject: [PATCH 48/66] use a case-split for diagnostic severity levels --- generator/src/main.rs | 24 ++++++++++++++++++++---- ql/src/ruby.dbscheme | 26 +++++++++++++++++--------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/generator/src/main.rs b/generator/src/main.rs index 6f5666c9033..c3561e8dc68 100644 --- a/generator/src/main.rs +++ b/generator/src/main.rs @@ -148,7 +148,6 @@ fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec = Set::new(); let token_kinds: Map<&str, usize> = nodes @@ -249,6 +248,11 @@ fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec() -> dbscheme::Entry<'a> { }) } -fn create_diagnostics_table<'a>() -> dbscheme::Entry<'a> { - dbscheme::Entry::Table(dbscheme::Table { +fn create_diagnostics<'a>() -> (dbscheme::Case<'a>, dbscheme::Table<'a>) { + let table = dbscheme::Table { name: "diagnostics", keysets: None, columns: vec![ @@ -639,7 +643,19 @@ fn create_diagnostics_table<'a>() -> dbscheme::Entry<'a> { ql_type_is_ref: true, }, ], - }) + }; + let severities: Vec<(usize, &str)> = vec![ + (0, "diagnostic_hidden"), + (1, "diagnostic_info"), + (2, "diagnostic_warning"), + (3, "diagnostic_error"), + ]; + let case = dbscheme::Case { + name: "diagnostic", + column: "severity", + branches: severities, + }; + (case, table) } fn main() { diff --git a/ql/src/ruby.dbscheme b/ql/src/ruby.dbscheme index dcbc1684061..e9164e21ebf 100644 --- a/ql/src/ruby.dbscheme +++ b/ql/src/ruby.dbscheme @@ -46,15 +46,6 @@ 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 -); - @underscore_arg = @assignment | @binary | @conditional | @operator_assignment | @range | @unary | @underscore_primary @underscore_lhs = @call | @element_reference | @scope_resolution | @token_false | @token_nil | @token_true | @underscore_variable @@ -1246,6 +1237,23 @@ case @token.kind of ; +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 + 0 = @diagnostic_hidden +| 1 = @diagnostic_info +| 2 = @diagnostic_warning +| 3 = @diagnostic_error +; + + @ast_node = @alias | @argument_list | @array | @assignment | @bare_string | @bare_symbol | @begin | @begin_block | @binary | @block | @block_argument | @block_parameter | @block_parameters | @break | @call | @case__ | @chained_string | @class | @conditional | @delimited_symbol | @destructured_left_assignment | @destructured_parameter | @do | @do_block | @element_reference | @else | @elsif | @end_block | @ensure | @exception_variable | @exceptions | @for | @hash | @hash_splat_argument | @hash_splat_parameter | @heredoc_body | @if | @if_modifier | @in | @interpolation | @keyword_parameter | @lambda | @lambda_parameters | @left_assignment_list | @method | @method_parameters | @module | @next | @operator_assignment | @optional_parameter | @pair | @parenthesized_statements | @pattern | @program | @range | @rational | @redo | @regex | @rescue | @rescue_modifier | @rest_assignment | @retry | @return | @right_assignment_list | @scope_resolution | @setter | @singleton_class | @singleton_method | @splat_argument | @splat_parameter | @string__ | @string_array | @subshell | @superclass | @symbol_array | @then | @token | @unary | @undef | @unless | @unless_modifier | @until | @until_modifier | @when | @while | @while_modifier | @yield @ast_node_parent = @ast_node | @file From 11376bc41114142c8bab66b4b20c65fc088b291d Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 12 May 2021 16:39:51 +0100 Subject: [PATCH 49/66] note that severity 3 corresponds to an error diagnostic level --- extractor/src/extractor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extractor/src/extractor.rs b/extractor/src/extractor.rs index b5ba70ae554..33d06358a2a 100644 --- a/extractor/src/extractor.rs +++ b/extractor/src/extractor.rs @@ -281,7 +281,7 @@ impl Visitor<'_> { "diagnostics", vec![ Arg::Label(id), - Arg::Int(3), + Arg::Int(3), // severity 3 = error Arg::String("parse_error".to_string()), Arg::String(error_message), Arg::String(full_error_message), From acdbd9859e408699eb7c8bf4121ffab75ff35d57 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 12 May 2021 16:45:31 +0100 Subject: [PATCH 50/66] simplify ExtractionError class defn --- ql/src/codeql_ruby/Diagnostics.qll | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ql/src/codeql_ruby/Diagnostics.qll b/ql/src/codeql_ruby/Diagnostics.qll index e2e28a84b07..d97030b57e7 100644 --- a/ql/src/codeql_ruby/Diagnostics.qll +++ b/ql/src/codeql_ruby/Diagnostics.qll @@ -47,9 +47,6 @@ class Diagnostic extends @diagnostic { } /** A diagnostic relating to a particular error in extracting a file. */ -class ExtractionError extends Diagnostic { - ExtractionError() { - this.getSeverity() = 3 and - this.getTag() = "parse_error" - } +class ExtractionError extends Diagnostic, @diagnostic_error { + ExtractionError() { this.getTag() = "parse_error" } } From ff06e724b1c5dbe281008f57324db4ea4922108d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 12 May 2021 16:28:35 +0200 Subject: [PATCH 51/66] AST synthesis framework --- ql/consistency-queries/AstConsistency.ql | 12 +- ql/src/codeql_ruby/AST.qll | 29 +- ql/src/codeql_ruby/ast/Call.qll | 9 +- ql/src/codeql_ruby/ast/Expr.qll | 14 +- ql/src/codeql_ruby/ast/Operation.qll | 94 +++++- ql/src/codeql_ruby/ast/Parameter.qll | 19 +- ql/src/codeql_ruby/ast/Pattern.qll | 8 +- ql/src/codeql_ruby/ast/Variable.qll | 67 +---- ql/src/codeql_ruby/ast/internal/AST.qll | 267 ++++++++++++++---- ql/src/codeql_ruby/ast/internal/Module.qll | 4 +- ql/src/codeql_ruby/ast/internal/Synthesis.qll | 173 ++++++++++++ ql/src/codeql_ruby/ast/internal/Variable.qll | 164 ++++++++++- ql/src/codeql_ruby/controlflow/CfgNodes.qll | 11 +- .../codeql_ruby/controlflow/internal/Cfg.ql | 28 -- .../codeql_ruby/controlflow/internal/Cfg.qll | 32 +++ .../internal/ControlFlowGraphImpl.qll | 21 ++ ql/src/codeql_ruby/printAst.qll | 36 ++- ql/test/library-tests/ast/Ast.ql | 1 - ql/test/library-tests/ast/AstDesugar.expected | 180 ++++++++++++ ql/test/library-tests/ast/AstDesugar.ql | 9 + .../ast/operations/assignment.expected | 16 ++ .../ast/operations/binary.expected | 32 +++ .../ast/operations/operation.expected | 64 +++++ .../controlflow/graph/Cfg.expected | 118 ++++++-- .../library-tests/controlflow/graph/Cfg.ql | 9 + .../library-tests/controlflow/graph/Cfg.qlref | 1 - .../dataflow/local/DataflowStep.expected | 5 +- ql/test/library-tests/variables/ssa.expected | 46 +-- .../variables/varaccess.expected | 16 +- 29 files changed, 1235 insertions(+), 250 deletions(-) create mode 100644 ql/src/codeql_ruby/ast/internal/Synthesis.qll delete mode 100644 ql/src/codeql_ruby/controlflow/internal/Cfg.ql create mode 100644 ql/src/codeql_ruby/controlflow/internal/Cfg.qll create mode 100644 ql/test/library-tests/ast/AstDesugar.expected create mode 100644 ql/test/library-tests/ast/AstDesugar.ql create mode 100644 ql/test/library-tests/controlflow/graph/Cfg.ql delete mode 100644 ql/test/library-tests/controlflow/graph/Cfg.qlref diff --git a/ql/consistency-queries/AstConsistency.ql b/ql/consistency-queries/AstConsistency.ql index 6977374b5ed..beb4e08fb76 100644 --- a/ql/consistency-queries/AstConsistency.ql +++ b/ql/consistency-queries/AstConsistency.ql @@ -15,6 +15,14 @@ query predicate missingParent(AstNode node, string cls) { query predicate multipleParents(AstNode node, AstNode parent, string cls) { parent = node.getParent() and - count(node.getParent()) > 1 and - cls = getAPrimaryQlClass(parent) + cls = getAPrimaryQlClass(parent) and + exists(AstNode one, AstNode two | + one = node.getParent() and + two = node.getParent() and + one != two + | + one.isSynthesized() and two.isSynthesized() + or + not one.isSynthesized() and not two.isSynthesized() + ) } diff --git a/ql/src/codeql_ruby/AST.qll b/ql/src/codeql_ruby/AST.qll index 0c895478ddf..26b37c2d192 100644 --- a/ql/src/codeql_ruby/AST.qll +++ b/ql/src/codeql_ruby/AST.qll @@ -14,6 +14,7 @@ import ast.Statement import ast.Variable private import ast.internal.AST private import ast.internal.Scope +private import ast.internal.Synthesis /** * A node in the abstract syntax tree. This class is the base class for all Ruby @@ -56,7 +57,11 @@ class AstNode extends TAstNode { final AstNode getAChild() { result = this.getAChild(_) } /** Gets the parent of this `AstNode`, if this node is not a root node. */ - final AstNode getParent() { result.getAChild() = this } + final AstNode getParent() { + result.getAChild() = this + or + result.getAChild().getDesugared() = this + } /** * Gets a child of this node, which can also be retrieved using a predicate @@ -75,5 +80,25 @@ class AstNode extends TAstNode { * foo(123) * ``` */ - predicate isSynthesized() { this instanceof TImplicitSelf } + final predicate isSynthesized() { this = getSynthChild(_, _) } + + /** + * Gets the desugared version of this AST node, if any. + * + * For example, the desugared version of + * + * ```rb + * x += y + * ``` + * + * is + * + * ```rb + * x = x + y + * ``` + * + * when `x` is a variable. Whenever an AST node can be desugared, + * then the desugared version is used in the control-flow graph. + */ + final AstNode getDesugared() { result = getSynthChild(this, -1) } } diff --git a/ql/src/codeql_ruby/ast/Call.qll b/ql/src/codeql_ruby/ast/Call.qll index b65a26a22c5..7c5ae5a7893 100644 --- a/ql/src/codeql_ruby/ast/Call.qll +++ b/ql/src/codeql_ruby/ast/Call.qll @@ -137,7 +137,7 @@ private class IdentifierMethodCall extends MethodCall, TIdentifierMethodCall { final override string getMethodName() { result = getMethodName(this, g.getValue()) } - final override Self getReceiver() { result = TImplicitSelf(g) } + final override Self getReceiver() { result = TSelfSynth(this, 0) } } private class ScopeResolutionMethodCall extends MethodCall, TScopeResolutionMethodCall { @@ -162,12 +162,7 @@ private class RegularMethodCall extends MethodCall, TRegularMethodCall { not exists(g.getReceiver()) and toGenerated(result) = g.getMethod().(Generated::ScopeResolution).getScope() or - // 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.getReceiver()) and - not exists(g.getMethod().(Generated::ScopeResolution).getScope()) and - result = TImplicitSelf(g) + result = TSelfSynth(this, 0) } final override string getMethodName() { diff --git a/ql/src/codeql_ruby/ast/Expr.qll b/ql/src/codeql_ruby/ast/Expr.qll index 59bd9335a8c..17b52b97268 100644 --- a/ql/src/codeql_ruby/ast/Expr.qll +++ b/ql/src/codeql_ruby/ast/Expr.qll @@ -206,17 +206,23 @@ class BodyStmt extends StmtSequence, TBodyStmt { * ``` */ class ParenthesizedExpr extends StmtSequence, TParenthesizedExpr { - private Generated::ParenthesizedStatements g; - - ParenthesizedExpr() { this = TParenthesizedExpr(g) } - final override string getAPrimaryQlClass() { result = "ParenthesizedExpr" } final override string toString() { result = "( ... )" } +} + +private class ParenthesizedExprReal extends ParenthesizedExpr, TParenthesizedExprReal { + private Generated::ParenthesizedStatements g; + + ParenthesizedExprReal() { this = TParenthesizedExprReal(g) } final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } } +private class ParenthesizedExprSynth extends ParenthesizedExpr, TParenthesizedExprSynth { + final override Stmt getStmt(int n) { synthChild(this, n, result) } +} + /** * A pair expression. For example, in a hash: * ```rb diff --git a/ql/src/codeql_ruby/ast/Operation.qll b/ql/src/codeql_ruby/ast/Operation.qll index b5acf8c8116..7b4394cc45e 100644 --- a/ql/src/codeql_ruby/ast/Operation.qll +++ b/ql/src/codeql_ruby/ast/Operation.qll @@ -101,12 +101,6 @@ class DefinedExpr extends UnaryOperation, TDefinedExpr { /** A binary operation. */ class BinaryOperation extends Operation, TBinaryOperation { - private Generated::Binary g; - - BinaryOperation() { g = toGenerated(this) } - - final override string getOperator() { result = g.getOperator() } - final override Expr getAnOperand() { result = this.getLeftOperand() or result = this.getRightOperand() } @@ -122,10 +116,28 @@ class BinaryOperation extends Operation, TBinaryOperation { } /** Gets the left operand of this binary operation. */ - final Stmt getLeftOperand() { toGenerated(result) = g.getLeft() } + Stmt getLeftOperand() { none() } /** Gets the right operand of this binary operation. */ - final Stmt getRightOperand() { toGenerated(result) = g.getRight() } + Stmt getRightOperand() { none() } +} + +private class BinaryOperationReal extends BinaryOperation { + private Generated::Binary g; + + BinaryOperationReal() { g = toGenerated(this) } + + final override string getOperator() { result = g.getOperator() } + + final override Stmt getLeftOperand() { toGenerated(result) = g.getLeft() } + + final override Stmt getRightOperand() { toGenerated(result) = g.getRight() } +} + +abstract private class BinaryOperationSynth extends BinaryOperation { + final override Stmt getLeftOperand() { synthChild(this, 0, result) } + + final override Stmt getRightOperand() { synthChild(this, 1, result) } } /** @@ -143,6 +155,10 @@ class AddExpr extends BinaryArithmeticOperation, TAddExpr { final override string getAPrimaryQlClass() { result = "AddExpr" } } +private class AddExprSynth extends AddExpr, BinaryOperationSynth, TAddExprSynth { + final override string getOperator() { result = "+" } +} + /** * A subtract expression. * ```rb @@ -153,6 +169,10 @@ class SubExpr extends BinaryArithmeticOperation, TSubExpr { final override string getAPrimaryQlClass() { result = "SubExpr" } } +private class SubExprSynth extends SubExpr, BinaryOperationSynth, TSubExprSynth { + final override string getOperator() { result = "-" } +} + /** * A multiply expression. * ```rb @@ -163,6 +183,10 @@ class MulExpr extends BinaryArithmeticOperation, TMulExpr { final override string getAPrimaryQlClass() { result = "MulExpr" } } +private class MulExprSynth extends MulExpr, BinaryOperationSynth, TMulExprSynth { + final override string getOperator() { result = "*" } +} + /** * A divide expression. * ```rb @@ -173,6 +197,10 @@ class DivExpr extends BinaryArithmeticOperation, TDivExpr { final override string getAPrimaryQlClass() { result = "DivExpr" } } +private class DivExprSynth extends DivExpr, BinaryOperationSynth, TDivExprSynth { + final override string getOperator() { result = "/" } +} + /** * A modulo expression. * ```rb @@ -183,6 +211,10 @@ class ModuloExpr extends BinaryArithmeticOperation, TModuloExpr { final override string getAPrimaryQlClass() { result = "ModuloExpr" } } +private class ModuloExprSynth extends ModuloExpr, BinaryOperationSynth, TModuloExprSynth { + final override string getOperator() { result = "%" } +} + /** * An exponent expression. * ```rb @@ -193,6 +225,10 @@ class ExponentExpr extends BinaryArithmeticOperation, TExponentExpr { final override string getAPrimaryQlClass() { result = "ExponentExpr" } } +private class ExponentExprSynth extends ExponentExpr, BinaryOperationSynth, TExponentExprSynth { + final override string getOperator() { result = "**" } +} + /** * A binary logical operation. */ @@ -209,6 +245,10 @@ class LogicalAndExpr extends BinaryLogicalOperation, TLogicalAndExpr { final override string getAPrimaryQlClass() { result = "LogicalAndExpr" } } +private class LogicalAndExprSynth extends LogicalAndExpr, BinaryOperationSynth, TLogicalAndExprSynth { + final override string getOperator() { result = "&&" } +} + /** * A logical OR operation, using either `or` or `||`. * ```rb @@ -220,6 +260,10 @@ class LogicalOrExpr extends BinaryLogicalOperation, TLogicalOrExpr { final override string getAPrimaryQlClass() { result = "LogicalOrExpr" } } +private class LogicalOrExprSynth extends LogicalOrExpr, BinaryOperationSynth, TLogicalOrExprSynth { + final override string getOperator() { result = "||" } +} + /** * A binary bitwise operation. */ @@ -235,6 +279,10 @@ class LShiftExpr extends BinaryBitwiseOperation, TLShiftExpr { final override string getAPrimaryQlClass() { result = "LShiftExpr" } } +private class LShiftExprSynth extends LShiftExpr, BinaryOperationSynth, TLShiftExprSynth { + final override string getOperator() { result = "<<" } +} + /** * A right-shift operation. * ```rb @@ -245,6 +293,10 @@ class RShiftExpr extends BinaryBitwiseOperation, TRShiftExpr { final override string getAPrimaryQlClass() { result = "RShiftExpr" } } +private class RShiftExprSynth extends RShiftExpr, BinaryOperationSynth, TRShiftExprSynth { + final override string getOperator() { result = ">>" } +} + /** * A bitwise AND operation. * ```rb @@ -255,6 +307,10 @@ class BitwiseAndExpr extends BinaryBitwiseOperation, TBitwiseAndExpr { final override string getAPrimaryQlClass() { result = "BitwiseAndExpr" } } +private class BitwiseAndSynthExpr extends BitwiseAndExpr, BinaryOperationSynth, TBitwiseAndExprSynth { + final override string getOperator() { result = "&" } +} + /** * A bitwise OR operation. * ```rb @@ -265,6 +321,10 @@ class BitwiseOrExpr extends BinaryBitwiseOperation, TBitwiseOrExpr { final override string getAPrimaryQlClass() { result = "BitwiseOrExpr" } } +private class BitwiseOrSynthExpr extends BitwiseOrExpr, BinaryOperationSynth, TBitwiseOrExprSynth { + final override string getOperator() { result = "|" } +} + /** * An XOR (exclusive OR) operation. * ```rb @@ -275,6 +335,10 @@ class BitwiseXorExpr extends BinaryBitwiseOperation, TBitwiseXorExpr { final override string getAPrimaryQlClass() { result = "BitwiseXorExpr" } } +private class BitwiseXorSynthExpr extends BitwiseXorExpr, BinaryOperationSynth, TBitwiseXorExprSynth { + final override string getOperator() { result = "^" } +} + /** * A comparison operation. That is, either an equality operation or a * relational operation. @@ -455,17 +519,25 @@ class Assignment extends Operation, TAssignment { * ``` */ class AssignExpr extends Assignment, TAssignExpr { + final override string getOperator() { result = "=" } + + final override string getAPrimaryQlClass() { result = "AssignExpr" } +} + +private class AssignExprReal extends AssignExpr, TAssignExprReal { private Generated::Assignment g; - AssignExpr() { this = TAssignExpr(g) } + AssignExprReal() { this = TAssignExprReal(g) } final override Pattern getLeftOperand() { toGenerated(result) = g.getLeft() } final override Expr getRightOperand() { toGenerated(result) = g.getRight() } +} - final override string getOperator() { result = "=" } +private class AssignExprSynth extends AssignExpr, TAssignExprSynth { + final override Pattern getLeftOperand() { synthChild(this, 0, result) } - override string getAPrimaryQlClass() { result = "AssignExpr" } + final override Expr getRightOperand() { synthChild(this, 1, result) } } /** diff --git a/ql/src/codeql_ruby/ast/Parameter.qll b/ql/src/codeql_ruby/ast/Parameter.qll index 7f9c11b417b..d70c8cc7588 100644 --- a/ql/src/codeql_ruby/ast/Parameter.qll +++ b/ql/src/codeql_ruby/ast/Parameter.qll @@ -37,10 +37,7 @@ class TuplePatternParameter extends PatternParameter, TuplePattern, TTuplePatter final override string getAPrimaryQlClass() { result = "TuplePatternParameter" } - override AstNode getAChild(string pred) { - result = PatternParameter.super.getAChild(pred) or - result = TuplePattern.super.getAChild(pred) - } + override AstNode getAChild(string pred) { result = TuplePattern.super.getAChild(pred) } } /** A named parameter. */ @@ -60,8 +57,6 @@ class NamedParameter extends Parameter, TNamedParameter { final VariableAccess getDefiningAccess() { result = this.getVariable().getDefiningAccess() } override AstNode getAChild(string pred) { - result = Parameter.super.getAChild(pred) - or pred = "getDefiningAccess" and result = this.getDefiningAccess() } @@ -75,7 +70,7 @@ class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern, final override string getName() { result = g.getValue() } - final override LocalVariable getVariable() { result = TLocalVariable(_, _, g) } + final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g) } final override LocalVariable getAVariable() { result = this.getVariable() } @@ -99,7 +94,7 @@ class BlockParameter extends NamedParameter, TBlockParameter { final override string getName() { result = g.getName().getValue() } - final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) } + final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) } final override string toString() { result = "&" + this.getName() } @@ -122,7 +117,7 @@ class HashSplatParameter extends NamedParameter, THashSplatParameter { final override string getAPrimaryQlClass() { result = "HashSplatParameter" } - final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) } + final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) } final override string toString() { result = "**" + this.getName() } @@ -147,7 +142,7 @@ class KeywordParameter extends NamedParameter, TKeywordParameter { final override string getAPrimaryQlClass() { result = "KeywordParameter" } - final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) } + final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) } /** * Gets the default value, i.e. the value assigned to the parameter when one @@ -197,7 +192,7 @@ class OptionalParameter extends NamedParameter, TOptionalParameter { */ final Expr getDefaultValue() { toGenerated(result) = g.getValue() } - final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) } + final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) } final override string toString() { result = this.getName() } @@ -227,7 +222,7 @@ class SplatParameter extends NamedParameter, TSplatParameter { final override string getAPrimaryQlClass() { result = "SplatParameter" } - final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) } + final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) } final override string toString() { result = "*" + this.getName() } diff --git a/ql/src/codeql_ruby/ast/Pattern.qll b/ql/src/codeql_ruby/ast/Pattern.qll index 3f5d335ec05..e6d21242196 100644 --- a/ql/src/codeql_ruby/ast/Pattern.qll +++ b/ql/src/codeql_ruby/ast/Pattern.qll @@ -7,9 +7,13 @@ private import internal.Variable /** A pattern. */ class Pattern extends AstNode { Pattern() { - explicitAssignmentNode(toGenerated(this), _) or - implicitAssignmentNode(toGenerated(this)) or + explicitAssignmentNode(toGenerated(this), _) + or + implicitAssignmentNode(toGenerated(this)) + or implicitParameterAssignmentNode(toGenerated(this), _) + or + this = getSynthChild(any(AssignExpr ae), 0) } /** Gets a variable used in (or introduced by) this pattern. */ diff --git a/ql/src/codeql_ruby/ast/Variable.qll b/ql/src/codeql_ruby/ast/Variable.qll index bc2ab278e6c..07f0f6397a7 100644 --- a/ql/src/codeql_ruby/ast/Variable.qll +++ b/ql/src/codeql_ruby/ast/Variable.qll @@ -8,21 +8,17 @@ private import internal.Variable /** A variable declared in a scope. */ class Variable extends TVariable { - Variable::Range range; - - Variable() { range = this } - /** Gets the name of this variable. */ - final string getName() { result = range.getName() } + string getName() { none() } /** Gets a textual representation of this variable. */ final string toString() { result = this.getName() } /** Gets the location of this variable. */ - final Location getLocation() { result = range.getLocation() } + Location getLocation() { none() } /** Gets the scope this variable is declared in. */ - final Scope getDeclaringScope() { toGenerated(result) = range.getDeclaringScope() } + Scope getDeclaringScope() { none() } /** Gets an access to this variable. */ VariableAccess getAnAccess() { result.getVariable() = this } @@ -30,12 +26,10 @@ class Variable extends TVariable { /** A local variable. */ class LocalVariable extends Variable, TLocalVariable { - override LocalVariable::Range range; - - final override LocalVariableAccess getAnAccess() { result.getVariable() = this } + override LocalVariableAccess getAnAccess() { none() } /** Gets the access where this local variable is first introduced. */ - VariableAccess getDefiningAccess() { result = range.getDefiningAccess() } + VariableAccess getDefiningAccess() { none() } /** * Holds if this variable is captured. For example in @@ -55,14 +49,14 @@ class LocalVariable extends Variable, TLocalVariable { } /** A global variable. */ -class GlobalVariable extends Variable, TGlobalVariable { +class GlobalVariable extends VariableReal, TGlobalVariable { override GlobalVariable::Range range; final override GlobalVariableAccess getAnAccess() { result.getVariable() = this } } /** An instance variable. */ -class InstanceVariable extends Variable, TInstanceVariable { +class InstanceVariable extends VariableReal, TInstanceVariable { override InstanceVariable::Range range; /** Holds is this variable is a class instance variable. */ @@ -72,7 +66,7 @@ class InstanceVariable extends Variable, TInstanceVariable { } /** A class variable. */ -class ClassVariable extends Variable, TClassVariable { +class ClassVariable extends VariableReal, TClassVariable { override ClassVariable::Range range; final override ClassVariableAccess getAnAccess() { result.getVariable() = this } @@ -95,6 +89,8 @@ class VariableAccess extends Expr, TVariableAccess { */ predicate isExplicitWrite(AstNode assignment) { explicitWriteAccess(toGenerated(this), toGenerated(assignment)) + or + this = assignment.(AssignExpr).getLeftOperand() } /** @@ -125,22 +121,12 @@ class VariableWriteAccess extends VariableAccess { /** An access to a variable where the value is read. */ class VariableReadAccess extends VariableAccess { - VariableReadAccess() { - not this instanceof VariableWriteAccess - or - // `x` in `x += y` is considered both a read and a write - this = any(AssignOperation a).getLeftOperand() - } + VariableReadAccess() { not this instanceof VariableWriteAccess } } /** An access to a local variable. */ class LocalVariableAccess extends VariableAccess, TLocalVariableAccess { - private Generated::Identifier g; - private LocalVariable v; - - LocalVariableAccess() { this = TLocalVariableAccess(g, v) } - - final override LocalVariable getVariable() { result = v } + override LocalVariable getVariable() { none() } final override string getAPrimaryQlClass() { result = "LocalVariableAccess" } @@ -160,8 +146,6 @@ class LocalVariableAccess extends VariableAccess, TLocalVariableAccess { * the access to `x` in the second `puts x` is not. */ final predicate isCapturedAccess() { isCapturedAccess(this) } - - final override string toString() { result = g.getValue() } } /** An access to a local variable where the value is updated. */ @@ -172,16 +156,9 @@ class LocalVariableReadAccess extends LocalVariableAccess, VariableReadAccess { /** An access to a global variable. */ class GlobalVariableAccess extends VariableAccess, TGlobalVariableAccess { - private Generated::GlobalVariable g; - private GlobalVariable v; - - GlobalVariableAccess() { this = TGlobalVariableAccess(g, v) } - - final override GlobalVariable getVariable() { result = v } + override GlobalVariable getVariable() { none() } final override string getAPrimaryQlClass() { result = "GlobalVariableAccess" } - - final override string toString() { result = g.getValue() } } /** An access to a global variable where the value is updated. */ @@ -192,28 +169,14 @@ class GlobalVariableReadAccess extends GlobalVariableAccess, VariableReadAccess /** An access to an instance variable. */ class InstanceVariableAccess extends VariableAccess, TInstanceVariableAccess { - private Generated::InstanceVariable g; - private InstanceVariable v; - - InstanceVariableAccess() { this = TInstanceVariableAccess(g, v) } - - final override InstanceVariable getVariable() { result = v } + override InstanceVariable getVariable() { none() } final override string getAPrimaryQlClass() { result = "InstanceVariableAccess" } - - final override string toString() { result = g.getValue() } } /** An access to a class variable. */ class ClassVariableAccess extends VariableAccess, TClassVariableAccess { - private Generated::ClassVariable g; - private ClassVariable v; - - ClassVariableAccess() { this = TClassVariableAccess(g, v) } - - final override ClassVariable getVariable() { result = v } + override ClassVariable getVariable() { none() } final override string getAPrimaryQlClass() { result = "ClassVariableAccess" } - - final override string toString() { result = g.getValue() } } diff --git a/ql/src/codeql_ruby/ast/internal/AST.qll b/ql/src/codeql_ruby/ast/internal/AST.qll index a7ad94ec652..9dd3c35058e 100644 --- a/ql/src/codeql_ruby/ast/internal/AST.qll +++ b/ql/src/codeql_ruby/ast/internal/AST.qll @@ -3,6 +3,7 @@ private import TreeSitter private import codeql_ruby.ast.internal.Parameter private import codeql_ruby.ast.internal.Variable private import codeql_ruby.AST as AST +private import Synthesis module MethodName { predicate range(Generated::UnderscoreMethodName g) { @@ -16,11 +17,16 @@ module MethodName { @token_identifier or @token_instance_variable or @token_operator; } +private predicate mkSynthChild(SynthKind kind, AST::AstNode parent, int i) { + any(Synthesis s).child(parent, i, SynthChild(kind)) +} + cached private module Cached { cached newtype TAstNode = - TAddExpr(Generated::Binary g) { g instanceof @binary_plus } or + TAddExprReal(Generated::Binary g) { g instanceof @binary_plus } or + TAddExprSynth(AST::AstNode parent, int i) { mkSynthChild(AddExprKind(), parent, i) } or TAliasStmt(Generated::Alias g) or TArgumentList(Generated::AstNode g) { ( @@ -50,7 +56,8 @@ private module Cached { TAssignExponentExpr(Generated::OperatorAssignment g) { g instanceof @operator_assignment_starstarequal } or - TAssignExpr(Generated::Assignment g) or + TAssignExprReal(Generated::Assignment g) or + TAssignExprSynth(AST::AstNode parent, int i) { mkSynthChild(AssignExprKind(), parent, i) } or TAssignLShiftExpr(Generated::OperatorAssignment g) { g instanceof @operator_assignment_langlelangleequal } or @@ -72,9 +79,16 @@ private module Cached { TBareSymbolLiteral(Generated::BareSymbol g) or TBeginBlock(Generated::BeginBlock g) or TBeginExpr(Generated::Begin g) or - TBitwiseAndExpr(Generated::Binary g) { g instanceof @binary_ampersand } or - TBitwiseOrExpr(Generated::Binary g) { g instanceof @binary_pipe } or - TBitwiseXorExpr(Generated::Binary g) { g instanceof @binary_caret } or + TBitwiseAndExprReal(Generated::Binary g) { g instanceof @binary_ampersand } or + TBitwiseAndExprSynth(AST::AstNode parent, int i) { + mkSynthChild(BitwiseAndExprKind(), parent, i) + } or + TBitwiseOrExprReal(Generated::Binary g) { g instanceof @binary_pipe } or + TBitwiseOrExprSynth(AST::AstNode parent, int i) { mkSynthChild(BitwiseOrExprKind(), parent, i) } or + TBitwiseXorExprReal(Generated::Binary g) { g instanceof @binary_caret } or + TBitwiseXorExprSynth(AST::AstNode parent, int i) { + mkSynthChild(BitwiseXorExprKind(), parent, i) + } or TBlockArgument(Generated::BlockArgument g) or TBlockParameter(Generated::BlockParameter g) or TBraceBlock(Generated::Block g) { not g.getParent() instanceof Generated::Lambda } or @@ -83,9 +97,12 @@ private module Cached { TCaseExpr(Generated::Case g) or TCharacterLiteral(Generated::Character g) or TClassDeclaration(Generated::Class g) or - TClassVariableAccess(Generated::ClassVariable g, AST::ClassVariable v) { + TClassVariableAccessReal(Generated::ClassVariable g, AST::ClassVariable v) { ClassVariableAccess::range(g, v) } or + TClassVariableAccessSynth(AST::AstNode parent, int i, AST::ClassVariable v) { + mkSynthChild(ClassVariableAccessKind(v), parent, i) + } or TComplementExpr(Generated::Unary g) { g instanceof @unary_tilde } or TComplexLiteral(Generated::Complex g) or TDefinedExpr(Generated::Unary g) { g instanceof @unary_definedquestion } or @@ -93,7 +110,8 @@ private module Cached { TDestructuredLeftAssignment(Generated::DestructuredLeftAssignment g) { not strictcount(int i | exists(g.getParent().(Generated::LeftAssignmentList).getChild(i))) = 1 } or - TDivExpr(Generated::Binary g) { g instanceof @binary_slash } or + TDivExprReal(Generated::Binary g) { g instanceof @binary_slash } or + TDivExprSynth(AST::AstNode parent, int i) { mkSynthChild(DivExprKind(), parent, i) } or TDo(Generated::Do g) or TDoBlock(Generated::DoBlock g) { not g.getParent() instanceof Generated::Lambda } or TElementReference(Generated::ElementReference g) or @@ -103,17 +121,20 @@ private module Cached { TEndBlock(Generated::EndBlock g) or TEnsure(Generated::Ensure g) or TEqExpr(Generated::Binary g) { g instanceof @binary_equalequal } or - TExplicitSelf(Generated::Self g) or - TExponentExpr(Generated::Binary g) { g instanceof @binary_starstar } or + TExponentExprReal(Generated::Binary g) { g instanceof @binary_starstar } or + TExponentExprSynth(AST::AstNode parent, int i) { mkSynthChild(ExponentExprKind(), parent, i) } or TFalseLiteral(Generated::False g) or TFloatLiteral(Generated::Float g) { not any(Generated::Rational r).getChild() = g } or TForExpr(Generated::For g) or TForIn(Generated::In g) or // TODO REMOVE TGEExpr(Generated::Binary g) { g instanceof @binary_rangleequal } or TGTExpr(Generated::Binary g) { g instanceof @binary_rangle } or - TGlobalVariableAccess(Generated::GlobalVariable g, AST::GlobalVariable v) { + TGlobalVariableAccessReal(Generated::GlobalVariable g, AST::GlobalVariable v) { GlobalVariableAccess::range(g, v) } or + TGlobalVariableAccessSynth(AST::AstNode parent, int i, AST::GlobalVariable v) { + mkSynthChild(GlobalVariableAccessKind(v), parent, i) + } or THashKeySymbolLiteral(Generated::HashKeySymbol g) or THashLiteral(Generated::Hash g) or THashSplatArgument(Generated::HashSplatArgument g) or @@ -122,34 +143,44 @@ private module Cached { TIdentifierMethodCall(Generated::Identifier g) { isIdentifierMethodCall(g) } or TIf(Generated::If g) or TIfModifierExpr(Generated::IfModifier g) or - TImplicitSelf(Generated::AstNode g) { - isIdentifierMethodCall(g) - or - isRegularMethodCall(g) and - not exists(g.(Generated::Call).getReceiver()) and - not exists(g.(Generated::Call).getMethod().(Generated::ScopeResolution).getScope()) - } or - TInstanceVariableAccess(Generated::InstanceVariable g, AST::InstanceVariable v) { + TInstanceVariableAccessReal(Generated::InstanceVariable g, AST::InstanceVariable v) { InstanceVariableAccess::range(g, v) } or + TInstanceVariableAccessSynth(AST::AstNode parent, int i, AST::InstanceVariable v) { + mkSynthChild(InstanceVariableAccessKind(v), parent, i) + } or TIntegerLiteral(Generated::Integer g) { not any(Generated::Rational r).getChild() = g } or TKeywordParameter(Generated::KeywordParameter g) or TLEExpr(Generated::Binary g) { g instanceof @binary_langleequal } or - TLShiftExpr(Generated::Binary g) { g instanceof @binary_langlelangle } or + TLShiftExprReal(Generated::Binary g) { g instanceof @binary_langlelangle } or + TLShiftExprSynth(AST::AstNode parent, int i) { mkSynthChild(LShiftExprKind(), parent, i) } or TLTExpr(Generated::Binary g) { g instanceof @binary_langle } or TLambda(Generated::Lambda g) or TLeftAssignmentList(Generated::LeftAssignmentList g) or - TLocalVariableAccess(Generated::Identifier g, AST::LocalVariable v) { + TLocalVariableAccessReal(Generated::Identifier g, AST::LocalVariable v) { LocalVariableAccess::range(g, v) } or - TLogicalAndExpr(Generated::Binary g) { + TLocalVariableAccessSynth(AST::AstNode parent, int i, AST::LocalVariable v) { + mkSynthChild(LocalVariableAccessRealKind(v), parent, i) + or + mkSynthChild(LocalVariableAccessSynthKind(v), parent, i) + } or + TLogicalAndExprReal(Generated::Binary g) { g instanceof @binary_and or g instanceof @binary_ampersandampersand } or - TLogicalOrExpr(Generated::Binary g) { g instanceof @binary_or or g instanceof @binary_pipepipe } or + TLogicalAndExprSynth(AST::AstNode parent, int i) { + mkSynthChild(LogicalAndExprKind(), parent, i) + } or + TLogicalOrExprReal(Generated::Binary g) { + g instanceof @binary_or or g instanceof @binary_pipepipe + } or + TLogicalOrExprSynth(AST::AstNode parent, int i) { mkSynthChild(LogicalOrExprKind(), parent, i) } or TMethod(Generated::Method g) or TModuleDeclaration(Generated::Module g) or - TModuloExpr(Generated::Binary g) { g instanceof @binary_percent } or - TMulExpr(Generated::Binary g) { g instanceof @binary_star } or + TModuloExprReal(Generated::Binary g) { g instanceof @binary_percent } or + TModuloExprSynth(AST::AstNode parent, int i) { mkSynthChild(ModuloExprKind(), parent, i) } or + TMulExprReal(Generated::Binary g) { g instanceof @binary_star } or + TMulExprSynth(AST::AstNode parent, int i) { mkSynthChild(MulExprKind(), parent, i) } or TNEExpr(Generated::Binary g) { g instanceof @binary_bangequal } or TNextStmt(Generated::Next g) or TNilLiteral(Generated::Nil g) or @@ -157,8 +188,12 @@ private module Cached { TNotExpr(Generated::Unary g) { g instanceof @unary_bang or g instanceof @unary_not } or TOptionalParameter(Generated::OptionalParameter g) or TPair(Generated::Pair g) or - TParenthesizedExpr(Generated::ParenthesizedStatements g) or - TRShiftExpr(Generated::Binary g) { g instanceof @binary_ranglerangle } or + TParenthesizedExprReal(Generated::ParenthesizedStatements g) or + TParenthesizedExprSynth(AST::AstNode parent, int i) { + mkSynthChild(ParenthesizedExprKind(), parent, i) + } or + TRShiftExprReal(Generated::Binary g) { g instanceof @binary_ranglerangle } or + TRShiftExprSynth(AST::AstNode parent, int i) { mkSynthChild(RShiftExprKind(), parent, i) } or TRangeLiteral(Generated::Range g) or TRationalLiteral(Generated::Rational g) or TRedoStmt(Generated::Redo g) or @@ -187,6 +222,8 @@ private module Cached { i = g.getName() and not exists(Generated::Call c | c.getMethod() = g) } or + TSelfReal(Generated::Self g) or + TSelfSynth(AST::AstNode parent, int i) { mkSynthChild(SelfKind(), parent, i) } or TSimpleParameter(Generated::Identifier g) { g instanceof Parameter::Range } or TSimpleSymbolLiteral(Generated::SimpleSymbol g) or TSingletonClass(Generated::SingletonClass g) or @@ -201,7 +238,8 @@ private module Cached { TStringTextComponent(Generated::Token g) { g instanceof Generated::StringContent or g instanceof Generated::HeredocContent } or - TSubExpr(Generated::Binary g) { g instanceof @binary_minus } or + TSubExprReal(Generated::Binary g) { g instanceof @binary_minus } or + TSubExprSynth(AST::AstNode parent, int i) { mkSynthChild(SubExprKind(), parent, i) } or TSubshellLiteral(Generated::Subshell g) or TSymbolArrayLiteral(Generated::SymbolArray g) or TTernaryIfExpr(Generated::Conditional g) or @@ -245,7 +283,7 @@ private module Cached { */ cached Generated::AstNode toGenerated(AST::AstNode n) { - n = TAddExpr(result) or + n = TAddExprReal(result) or n = TAliasStmt(result) or n = TArgumentList(result) or n = TAssignAddExpr(result) or @@ -254,7 +292,7 @@ private module Cached { n = TAssignBitwiseXorExpr(result) or n = TAssignDivExpr(result) or n = TAssignExponentExpr(result) or - n = TAssignExpr(result) or + n = TAssignExprReal(result) or n = TAssignLShiftExpr(result) or n = TAssignLogicalAndExpr(result) or n = TAssignLogicalOrExpr(result) or @@ -266,9 +304,9 @@ private module Cached { n = TBareSymbolLiteral(result) or n = TBeginBlock(result) or n = TBeginExpr(result) or - n = TBitwiseAndExpr(result) or - n = TBitwiseOrExpr(result) or - n = TBitwiseXorExpr(result) or + n = TBitwiseAndExprReal(result) or + n = TBitwiseOrExprReal(result) or + n = TBitwiseXorExprReal(result) or n = TBlockArgument(result) or n = TBlockParameter(result) or n = TBraceBlock(result) or @@ -277,13 +315,13 @@ private module Cached { n = TCaseExpr(result) or n = TCharacterLiteral(result) or n = TClassDeclaration(result) or - n = TClassVariableAccess(result, _) or + n = TClassVariableAccessReal(result, _) or n = TComplementExpr(result) or n = TComplexLiteral(result) or n = TDefinedExpr(result) or n = TDelimitedSymbolLiteral(result) or n = TDestructuredLeftAssignment(result) or - n = TDivExpr(result) or + n = TDivExprReal(result) or n = TDo(result) or n = TDoBlock(result) or n = TElementReference(result) or @@ -293,15 +331,14 @@ private module Cached { n = TEndBlock(result) or n = TEnsure(result) or n = TEqExpr(result) or - n = TExplicitSelf(result) or - n = TExponentExpr(result) or + n = TExponentExprReal(result) or n = TFalseLiteral(result) or n = TFloatLiteral(result) or n = TForExpr(result) or n = TForIn(result) or // TODO REMOVE n = TGEExpr(result) or n = TGTExpr(result) or - n = TGlobalVariableAccess(result, _) or + n = TGlobalVariableAccessReal(result, _) or n = THashKeySymbolLiteral(result) or n = THashLiteral(result) or n = THashSplatArgument(result) or @@ -310,21 +347,21 @@ private module Cached { n = TIdentifierMethodCall(result) or n = TIf(result) or n = TIfModifierExpr(result) or - n = TInstanceVariableAccess(result, _) or + n = TInstanceVariableAccessReal(result, _) or n = TIntegerLiteral(result) or n = TKeywordParameter(result) or n = TLEExpr(result) or - n = TLShiftExpr(result) or + n = TLShiftExprReal(result) or n = TLTExpr(result) or n = TLambda(result) or n = TLeftAssignmentList(result) or - n = TLocalVariableAccess(result, _) or - n = TLogicalAndExpr(result) or - n = TLogicalOrExpr(result) or + n = TLocalVariableAccessReal(result, _) or + n = TLogicalAndExprReal(result) or + n = TLogicalOrExprReal(result) or n = TMethod(result) or n = TModuleDeclaration(result) or - n = TModuloExpr(result) or - n = TMulExpr(result) or + n = TModuloExprReal(result) or + n = TMulExprReal(result) or n = TNEExpr(result) or n = TNextStmt(result) or n = TNilLiteral(result) or @@ -332,8 +369,8 @@ private module Cached { n = TNotExpr(result) or n = TOptionalParameter(result) or n = TPair(result) or - n = TParenthesizedExpr(result) or - n = TRShiftExpr(result) or + n = TParenthesizedExprReal(result) or + n = TRShiftExprReal(result) or n = TRangeLiteral(result) or n = TRationalLiteral(result) or n = TRedoStmt(result) or @@ -349,6 +386,7 @@ private module Cached { n = TReturnStmt(result) or n = TScopeResolutionConstantAccess(result, _) or n = TScopeResolutionMethodCall(result, _) or + n = TSelfReal(result) or n = TSimpleParameter(result) or n = TSimpleSymbolLiteral(result) or n = TSingletonClass(result) or @@ -361,7 +399,7 @@ private module Cached { n = TStringEscapeSequenceComponent(result) or n = TStringInterpolationComponent(result) or n = TStringTextComponent(result) or - n = TSubExpr(result) or + n = TSubExprReal(result) or n = TSubshellLiteral(result) or n = TSymbolArrayLiteral(result) or n = TTernaryIfExpr(result) or @@ -385,14 +423,105 @@ private module Cached { n = TYieldCall(result) } + /** Gets the `i`th synthesized child of `parent`. */ + cached + AST::AstNode getSynthChild(AST::AstNode parent, int i) { + exists(SynthKind kind | mkSynthChild(kind, parent, i) | + kind = AddExprKind() and + result = TAddExprSynth(parent, i) + or + kind = AssignExprKind() and + result = TAssignExprSynth(parent, i) + or + kind = BitwiseAndExprKind() and + result = TBitwiseAndExprSynth(parent, i) + or + kind = BitwiseOrExprKind() and + result = TBitwiseOrExprSynth(parent, i) + or + kind = BitwiseXorExprKind() and + result = TBitwiseXorExprSynth(parent, i) + or + exists(AST::ClassVariable v | + kind = ClassVariableAccessKind(v) and + result = TClassVariableAccessSynth(parent, i, v) + ) + or + kind = DivExprKind() and + result = TDivExprSynth(parent, i) + or + kind = ExponentExprKind() and + result = TExponentExprSynth(parent, i) + or + exists(AST::GlobalVariable v | + kind = GlobalVariableAccessKind(v) and + result = TGlobalVariableAccessSynth(parent, i, v) + ) + or + exists(AST::InstanceVariable v | + kind = InstanceVariableAccessKind(v) and + result = TInstanceVariableAccessSynth(parent, i, v) + ) + or + kind = LShiftExprKind() and + result = TLShiftExprSynth(parent, i) + or + exists(AST::LocalVariable v | result = TLocalVariableAccessSynth(parent, i, v) | + kind = LocalVariableAccessRealKind(v) + or + kind = LocalVariableAccessSynthKind(v) + ) + or + kind = LogicalAndExprKind() and + result = TLogicalAndExprSynth(parent, i) + or + kind = LogicalOrExprKind() and + result = TLogicalOrExprSynth(parent, i) + or + kind = ModuloExprKind() and + result = TModuloExprSynth(parent, i) + or + kind = MulExprKind() and + result = TMulExprSynth(parent, i) + or + kind = ParenthesizedExprKind() and + result = TParenthesizedExprSynth(parent, i) + or + kind = RShiftExprKind() and + result = TRShiftExprSynth(parent, i) + or + kind = SelfKind() and + result = TSelfSynth(parent, i) + or + kind = SubExprKind() and + result = TSubExprSynth(parent, i) + ) + } + + /** + * Holds if the `i`th child of `parent` is `child`. Either `parent` or + * `child` (or both) is a synthesized node. + */ + cached + predicate synthChild(AST::AstNode parent, int i, AST::AstNode child) { + child = getSynthChild(parent, i) + or + any(Synthesis s).child(parent, i, RealChild(child)) + } + /** * Like `toGenerated`, but also returns generated nodes for synthesized AST * nodes. */ cached Generated::AstNode toGeneratedInclSynth(AST::AstNode n) { - result = toGenerated(n) or - n = TImplicitSelf(result) + result = toGenerated(n) + or + not exists(toGenerated(n)) and + exists(AST::AstNode parent | + synthChild(parent, _, n) and + result = toGeneratedInclSynth(parent) + ) } } @@ -421,7 +550,7 @@ class TConditionalLoop = TWhileExpr or TUntilExpr or TWhileModifierExpr or TUnti class TLoop = TConditionalLoop or TForExpr; -class TSelf = TExplicitSelf or TImplicitSelf; +class TSelf = TSelfReal or TSelfSynth; class TExpr = TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or @@ -433,6 +562,8 @@ class TStmtSequence = TBeginBlock or TEndBlock or TThen or TElse or TDo or TEnsure or TStringInterpolationComponent or TBlock or TBodyStmt or TParenthesizedExpr; +class TParenthesizedExpr = TParenthesizedExprReal or TParenthesizedExprSynth; + class TBodyStmt = TBeginExpr or TModuleBase or TMethod or TLambda or TDoBlock or TSingletonMethod; class TLiteral = @@ -485,17 +616,45 @@ class TBinaryOperation = class TBinaryArithmeticOperation = TAddExpr or TSubExpr or TMulExpr or TDivExpr or TModuloExpr or TExponentExpr; +class TAddExpr = TAddExprReal or TAddExprSynth; + +class TSubExpr = TSubExprReal or TSubExprSynth; + +class TMulExpr = TMulExprReal or TMulExprSynth; + +class TDivExpr = TDivExprReal or TDivExprSynth; + +class TModuloExpr = TModuloExprReal or TModuloExprSynth; + +class TExponentExpr = TExponentExprReal or TExponentExprSynth; + class TBinaryLogicalOperation = TLogicalAndExpr or TLogicalOrExpr; +class TLogicalAndExpr = TLogicalAndExprReal or TLogicalAndExprSynth; + +class TLogicalOrExpr = TLogicalOrExprReal or TLogicalOrExprSynth; + class TBinaryBitwiseOperation = TLShiftExpr or TRShiftExpr or TBitwiseAndExpr or TBitwiseOrExpr or TBitwiseXorExpr; +class TLShiftExpr = TLShiftExprReal or TLShiftExprSynth; + +class TRShiftExpr = TRShiftExprReal or TRShiftExprSynth; + +class TBitwiseAndExpr = TBitwiseAndExprReal or TBitwiseAndExprSynth; + +class TBitwiseOrExpr = TBitwiseOrExprReal or TBitwiseOrExprSynth; + +class TBitwiseXorExpr = TBitwiseXorExprReal or TBitwiseXorExprSynth; + class TComparisonOperation = TEqualityOperation or TRelationalOperation; class TEqualityOperation = TEqExpr or TNEExpr or TCaseEqExpr; class TRelationalOperation = TGTExpr or TGEExpr or TLTExpr or TLEExpr; +class TAssignExpr = TAssignExprReal or TAssignExprSynth; + class TAssignment = TAssignExpr or TAssignOperation; class TAssignOperation = @@ -531,3 +690,11 @@ class TTuplePattern = TTuplePatternParameter or TDestructuredLeftAssignment or T class TVariableAccess = TLocalVariableAccess or TGlobalVariableAccess or TInstanceVariableAccess or TClassVariableAccess; + +class TLocalVariableAccess = TLocalVariableAccessReal or TLocalVariableAccessSynth; + +class TGlobalVariableAccess = TGlobalVariableAccessReal or TGlobalVariableAccessSynth; + +class TInstanceVariableAccess = TInstanceVariableAccessReal or TInstanceVariableAccessSynth; + +class TClassVariableAccess = TClassVariableAccessReal or TClassVariableAccessSynth; diff --git a/ql/src/codeql_ruby/ast/internal/Module.qll b/ql/src/codeql_ruby/ast/internal/Module.qll index d7708271e11..1a0b56f961d 100644 --- a/ql/src/codeql_ruby/ast/internal/Module.qll +++ b/ql/src/codeql_ruby/ast/internal/Module.qll @@ -67,7 +67,7 @@ private module Cached { m = resolveScopeExpr(c.getReceiver()) or m = enclosingModule(c).getModule() and - c.receiverIsSelf() + c.getReceiver() instanceof Self ) and result = resolveScopeExpr(c.getAnArgument()) ) @@ -81,7 +81,7 @@ private module Cached { m = resolveScopeExpr(c.getReceiver()) or m = enclosingModule(c).getModule() and - c.receiverIsSelf() + c.getReceiver() instanceof Self ) and result = resolveScopeExpr(c.getAnArgument()) ) diff --git a/ql/src/codeql_ruby/ast/internal/Synthesis.qll b/ql/src/codeql_ruby/ast/internal/Synthesis.qll new file mode 100644 index 00000000000..6cdca0db8e8 --- /dev/null +++ b/ql/src/codeql_ruby/ast/internal/Synthesis.qll @@ -0,0 +1,173 @@ +/** Provides predicates for synthesizing AST nodes. */ + +private import AST +private import TreeSitter +private import codeql_ruby.ast.internal.Parameter +private import codeql_ruby.ast.internal.Variable +private import codeql_ruby.AST + +/** A synthesized AST node kind. */ +newtype SynthKind = + AddExprKind() or + AssignExprKind() or + BitwiseAndExprKind() or + BitwiseOrExprKind() or + BitwiseXorExprKind() or + ClassVariableAccessKind(ClassVariable v) or + DivExprKind() or + ExponentExprKind() or + GlobalVariableAccessKind(GlobalVariable v) or + InstanceVariableAccessKind(InstanceVariable v) or + LShiftExprKind() or + LocalVariableAccessRealKind(LocalVariableReal v) or + LocalVariableAccessSynthKind(TLocalVariableSynth v) or + LogicalAndExprKind() or + LogicalOrExprKind() or + ModuloExprKind() or + MulExprKind() or + ParenthesizedExprKind() or + RShiftExprKind() or + SelfKind() or + SubExprKind() + +/** + * An AST child. + * + * Either a new synthesized node or a reference to an existing node. + */ +newtype Child = + SynthChild(SynthKind k) or + RealChild(AstNode n) + +private newtype TSynthesis = MkSynthesis() + +/** A class used for synthesizing AST nodes. */ +class Synthesis extends TSynthesis { + /** + * Holds if a node should be synthesized as the `i`th child of `parent`, or if + * a non-synthesized node should be the `i`th child of synthesized node `parent`. + * + * `i = -1` is used to represent that the synthesized node is a desugared version + * of its parent. + */ + predicate child(AstNode parent, int i, Child child) { none() } + + /** + * Holds if a local variable, identified by `i`, should be synthesized for AST + * node `n`. + */ + predicate localVariable(AstNode n, int i) { none() } + + /** + * Holds if `n` should be excluded from `ControlFlowTree` in the CFG construction. + */ + predicate excludeFromControlFlowTree(AstNode n) { none() } + + final string toString() { none() } +} + +private module ImplicitSelfSynthesis { + private class IdentifierMethodCallSelfSynthesis extends Synthesis { + final override predicate child(AstNode parent, int i, Child child) { + child = SynthChild(SelfKind()) and + parent = TIdentifierMethodCall(_) and + i = 0 + } + } + + private class RegularMethodCallSelfSynthesis extends Synthesis { + final override predicate child(AstNode parent, int i, Child child) { + child = SynthChild(SelfKind()) and + i = 0 and + exists(Generated::AstNode g | + parent = 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.(Generated::Call).getReceiver()) and + not exists(g.(Generated::Call).getMethod().(Generated::ScopeResolution).getScope()) + ) + } + } +} + +private module AssignOperationDesugar { + /** + * Gets the operator kind to synthesize for operator assignment `ao`. + */ + private SynthKind getKind(AssignOperation ao) { + ao instanceof AssignAddExpr and result = AddExprKind() + or + ao instanceof AssignSubExpr and result = SubExprKind() + or + ao instanceof AssignMulExpr and result = MulExprKind() + or + ao instanceof AssignDivExpr and result = DivExprKind() + or + ao instanceof AssignModuloExpr and result = ModuloExprKind() + or + ao instanceof AssignExponentExpr and result = ExponentExprKind() + or + ao instanceof AssignLogicalAndExpr and result = LogicalAndExprKind() + or + ao instanceof AssignLogicalOrExpr and result = LogicalOrExprKind() + or + ao instanceof AssignLShiftExpr and result = LShiftExprKind() + or + ao instanceof AssignRShiftExpr and result = RShiftExprKind() + or + ao instanceof AssignBitwiseAndExpr and result = BitwiseAndExprKind() + or + ao instanceof AssignBitwiseOrExpr and result = BitwiseOrExprKind() + or + ao instanceof AssignBitwiseXorExpr and result = BitwiseXorExprKind() + } + + /** + * ```rb + * x += y + * ``` + * + * desguars to + * + * ```rb + * x = x + y + * ``` + * + * when `x` is a variable. + */ + private class VariableAssignOperationSynthesis extends Synthesis { + final override predicate child(AstNode parent, int i, Child child) { + exists(AssignOperation ao, VariableReal v | + v = ao.getLeftOperand().(VariableAccessReal).getVariableReal() + | + parent = ao and + i = -1 and + child = SynthChild(AssignExprKind()) + or + exists(AstNode assign | assign = getSynthChild(ao, -1) | + parent = assign and + i = 0 and + child = RealChild(ao.getLeftOperand()) + or + parent = assign and + i = 1 and + child = SynthChild(getKind(ao)) + or + parent = getSynthChild(assign, 1) and + ( + i = 0 and + child = + SynthChild([ + LocalVariableAccessRealKind(v).(SynthKind), InstanceVariableAccessKind(v), + ClassVariableAccessKind(v), GlobalVariableAccessKind(v) + ]) + or + i = 1 and + child = RealChild(ao.getRightOperand()) + ) + ) + ) + } + } +} diff --git a/ql/src/codeql_ruby/ast/internal/Variable.qll b/ql/src/codeql_ruby/ast/internal/Variable.qll index fcd1e428862..456286f20a2 100644 --- a/ql/src/codeql_ruby/ast/internal/Variable.qll +++ b/ql/src/codeql_ruby/ast/internal/Variable.qll @@ -4,6 +4,7 @@ private import codeql_ruby.AST private import codeql_ruby.ast.internal.AST private import codeql_ruby.ast.internal.Parameter private import codeql_ruby.ast.internal.Scope +private import codeql_ruby.ast.internal.Synthesis /** * Holds if `n` is in the left-hand-side of an explicit assignment `assignment`. @@ -128,7 +129,7 @@ private module Cached { other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn() ) } or - TLocalVariable(Scope::Range scope, string name, Generated::Identifier i) { + TLocalVariableReal(Scope::Range scope, string name, Generated::Identifier i) { scopeDefinesParameterVariable(scope, name, i) or i = @@ -139,7 +140,8 @@ private module Cached { ) and not scopeDefinesParameterVariable(scope, name, _) and not inherits(scope, name, _) - } + } or + TLocalVariableSynth(AstNode n, int i) { any(Synthesis s).localVariable(n, i) } // Db types that can be vcalls private class VcallToken = @@ -288,7 +290,7 @@ private module Cached { } cached - predicate access(Generated::Identifier access, Variable::Range variable) { + predicate access(Generated::Identifier access, VariableReal::Range variable) { exists(string name | variable.getName() = name and name = access.getValue() @@ -372,8 +374,10 @@ private predicate inherits(Scope::Range scope, string name, Scope::Range outer) ) } -module Variable { - class Range extends TVariable { +class TVariableReal = TGlobalVariable or TClassVariable or TInstanceVariable or TLocalVariableReal; + +module VariableReal { + class Range extends TVariableReal { abstract string getName(); string toString() { result = this.getName() } @@ -384,13 +388,15 @@ module Variable { } } +class TLocalVariable = TLocalVariableReal or TLocalVariableSynth; + module LocalVariable { - class Range extends Variable::Range, TLocalVariable { + class Range extends VariableReal::Range, TLocalVariableReal { private Scope::Range scope; private string name; private Generated::Identifier i; - Range() { this = TLocalVariable(scope, name, i) } + Range() { this = TLocalVariableReal(scope, name, i) } final override string getName() { result = name } @@ -402,8 +408,41 @@ module LocalVariable { } } +class VariableReal extends Variable, TVariableReal { + VariableReal::Range range; + + VariableReal() { range = this } + + final override string getName() { result = range.getName() } + + final override Location getLocation() { result = range.getLocation() } + + final override Scope getDeclaringScope() { toGenerated(result) = range.getDeclaringScope() } +} + +class LocalVariableReal extends VariableReal, LocalVariable, TLocalVariableReal { + override LocalVariable::Range range; + + final override LocalVariableAccessReal getAnAccess() { result.getVariable() = this } + + final override VariableAccess getDefiningAccess() { result = range.getDefiningAccess() } +} + +class LocalVariableSynth extends LocalVariable, TLocalVariableSynth { + private AstNode n; + private int i; + + LocalVariableSynth() { this = TLocalVariableSynth(n, i) } + + final override string getName() { result = "__synth__" + i } + + final override Location getLocation() { result = n.getLocation() } + + final override Scope getDeclaringScope() { none() } // not relevant for synthesized variables +} + module GlobalVariable { - class Range extends Variable::Range, TGlobalVariable { + class Range extends VariableReal::Range, TGlobalVariable { private string name; Range() { this = TGlobalVariable(name) } @@ -417,7 +456,7 @@ module GlobalVariable { } module InstanceVariable { - class Range extends Variable::Range, TInstanceVariable { + class Range extends VariableReal::Range, TInstanceVariable { private ModuleBase::Range scope; private boolean instance; private string name; @@ -436,7 +475,7 @@ module InstanceVariable { } module ClassVariable { - class Range extends Variable::Range, TClassVariable { + class Range extends VariableReal::Range, TClassVariable { private ModuleBase::Range scope; private string name; private Generated::AstNode decl; @@ -464,16 +503,121 @@ module LocalVariableAccess { } } +class TVariableAccessReal = + TLocalVariableAccessReal or TGlobalVariableAccess or TInstanceVariableAccess or + TClassVariableAccess; + +abstract class VariableAccessReal extends VariableAccess, TVariableAccessReal { + abstract VariableReal getVariableReal(); +} + +private class LocalVariableAccessReal extends VariableAccessReal, LocalVariableAccess, + TLocalVariableAccessReal { + private Generated::Identifier g; + private LocalVariable v; + + LocalVariableAccessReal() { this = TLocalVariableAccessReal(g, v) } + + final override LocalVariable getVariable() { result = v } + + final override LocalVariableReal getVariableReal() { result = v } + + final override string toString() { result = g.getValue() } +} + +private class LocalVariableAccessSynth extends LocalVariableAccess, TLocalVariableAccessSynth { + private LocalVariable v; + + LocalVariableAccessSynth() { this = TLocalVariableAccessSynth(_, _, v) } + + final override LocalVariable getVariable() { result = v } + + final override string toString() { result = v.getName() } +} + module GlobalVariableAccess { predicate range(Generated::GlobalVariable n, GlobalVariable v) { n.getValue() = v.getName() } } +private class GlobalVariableAccessReal extends VariableAccessReal, GlobalVariableAccess, + TGlobalVariableAccessReal { + private Generated::GlobalVariable g; + private GlobalVariable v; + + GlobalVariableAccessReal() { this = TGlobalVariableAccessReal(g, v) } + + final override GlobalVariable getVariable() { result = v } + + final override GlobalVariable getVariableReal() { result = v } + + final override string toString() { result = g.getValue() } +} + +private class GlobalVariableAccessSynth extends GlobalVariableAccess, TGlobalVariableAccessSynth { + private GlobalVariable v; + + GlobalVariableAccessSynth() { this = TGlobalVariableAccessSynth(_, _, v) } + + final override GlobalVariable getVariable() { result = v } + + final override string toString() { result = v.getName() } +} + module InstanceVariableAccess { predicate range(Generated::InstanceVariable n, InstanceVariable v) { instanceVariableAccess(n, v) } } +private class InstanceVariableAccessReal extends VariableAccessReal, InstanceVariableAccess, + TInstanceVariableAccessReal { + private Generated::InstanceVariable g; + private InstanceVariable v; + + InstanceVariableAccessReal() { this = TInstanceVariableAccessReal(g, v) } + + final override InstanceVariable getVariable() { result = v } + + final override InstanceVariable getVariableReal() { result = v } + + final override string toString() { result = g.getValue() } +} + +private class InstanceVariableAccessSynth extends InstanceVariableAccess, + TInstanceVariableAccessSynth { + private InstanceVariable v; + + InstanceVariableAccessSynth() { this = TInstanceVariableAccessSynth(_, _, v) } + + final override InstanceVariable getVariable() { result = v } + + final override string toString() { result = v.getName() } +} + module ClassVariableAccess { predicate range(Generated::ClassVariable n, ClassVariable v) { classVariableAccess(n, v) } } + +private class ClassVariableAccessReal extends VariableAccessReal, ClassVariableAccess, + TClassVariableAccessReal { + private Generated::ClassVariable g; + private ClassVariable v; + + ClassVariableAccessReal() { this = TClassVariableAccessReal(g, v) } + + final override ClassVariable getVariable() { result = v } + + final override ClassVariable getVariableReal() { result = v } + + final override string toString() { result = g.getValue() } +} + +private class ClassVariableAccessSynth extends ClassVariableAccess, TClassVariableAccessSynth { + private ClassVariable v; + + ClassVariableAccessSynth() { this = TClassVariableAccessSynth(_, _, v) } + + final override ClassVariable getVariable() { result = v } + + final override string toString() { result = v.getName() } +} diff --git a/ql/src/codeql_ruby/controlflow/CfgNodes.qll b/ql/src/codeql_ruby/controlflow/CfgNodes.qll index 2c6f9f7a809..89c0ea8b3fd 100644 --- a/ql/src/codeql_ruby/controlflow/CfgNodes.qll +++ b/ql/src/codeql_ruby/controlflow/CfgNodes.qll @@ -159,6 +159,13 @@ abstract private class ExprChildMapping extends Expr { ) } + private Expr desugar(Expr n) { + result = n.getDesugared() + or + not exists(n.getDesugared()) and + result = n + } + /** * Holds if there is a control-flow path from `cfn` to `cfnChild`, where `cfn` * is a control-flow node for this expression, and `cfnChild` is a control-flow @@ -171,13 +178,13 @@ abstract private class ExprChildMapping extends Expr { exists(BasicBlock bb | this.reachesBasicBlockBase(child, cfn, bb) and cfnChild = bb.getANode() and - cfnChild = child.getAControlFlowNode() + cfnChild = desugar(child).getAControlFlowNode() ) or exists(BasicBlock bb | this.reachesBasicBlockRec(child, cfn, bb) and cfnChild = bb.getANode() and - cfnChild = child.getAControlFlowNode() + cfnChild = desugar(child).getAControlFlowNode() ) } } diff --git a/ql/src/codeql_ruby/controlflow/internal/Cfg.ql b/ql/src/codeql_ruby/controlflow/internal/Cfg.ql deleted file mode 100644 index a0b0200b346..00000000000 --- a/ql/src/codeql_ruby/controlflow/internal/Cfg.ql +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @kind graph - * @id rb/test/cfg - */ - -import codeql_ruby.CFG - -query predicate nodes(CfgNode n, string attr, string val) { - attr = "semmle.order" and - val = - any(int i | - n = - rank[i](CfgNode p | - | - p - order by - p.getLocation().getFile().getBaseName(), p.getLocation().getFile().getAbsolutePath(), - p.getLocation().getStartLine(), p.getLocation().getStartColumn() - ) - ).toString() -} - -query predicate edges(CfgNode pred, CfgNode succ, string attr, string val) { - exists(SuccessorType t | succ = pred.getASuccessor(t) | - attr = "semmle.label" and - if t instanceof SuccessorTypes::NormalSuccessor then val = "" else val = t.toString() - ) -} diff --git a/ql/src/codeql_ruby/controlflow/internal/Cfg.qll b/ql/src/codeql_ruby/controlflow/internal/Cfg.qll new file mode 100644 index 00000000000..ebc840a0e9f --- /dev/null +++ b/ql/src/codeql_ruby/controlflow/internal/Cfg.qll @@ -0,0 +1,32 @@ +/** + * Import this module into a `.ql` file of `@kind graph` to render a CFG. The + * graph is restricted to nodes from `RelevantCfgNode`. + */ + +private import codeql.Locations +import codeql_ruby.CFG + +abstract class RelevantCfgNode extends CfgNode { } + +query predicate nodes(RelevantCfgNode n, string attr, string val) { + attr = "semmle.order" and + val = + any(int i | + n = + rank[i](RelevantCfgNode p, Location l | + l = p.getLocation() + | + p + order by + l.getFile().getBaseName(), l.getFile().getAbsolutePath(), l.getStartLine(), + l.getStartColumn() + ) + ).toString() +} + +query predicate edges(RelevantCfgNode pred, RelevantCfgNode succ, string attr, string val) { + exists(SuccessorType t | succ = pred.getASuccessor(t) | + attr = "semmle.label" and + if t instanceof SuccessorTypes::NormalSuccessor then val = "" else val = t.toString() + ) +} diff --git a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll index bd5e91670fd..79d7d203c96 100644 --- a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll @@ -35,6 +35,7 @@ private import codeql_ruby.AST private import codeql_ruby.ast.internal.AST as ASTInternal private import codeql_ruby.ast.internal.Scope private import codeql_ruby.ast.Scope +private import codeql_ruby.ast.internal.Synthesis private import codeql_ruby.ast.internal.TreeSitter private import codeql_ruby.ast.internal.Variable private import codeql_ruby.controlflow.ControlFlowGraph @@ -85,6 +86,8 @@ module CfgScope { } abstract private class ControlFlowTree extends AstNode { + ControlFlowTree() { not any(Synthesis s).excludeFromControlFlowTree(this) } + /** * Holds if `first` is the first element executed within this AST node. */ @@ -284,6 +287,8 @@ module Trees { } private class AssignOperationTree extends StandardPostOrderTree, AssignOperation { + AssignOperationTree() { not this.getLeftOperand() instanceof VariableAccess } + final override ControlFlowTree getChildNode(int i) { result = this.getLeftOperand() and i = 0 or @@ -728,6 +733,22 @@ module Trees { } } + private class DesugaredTree extends ControlFlowTree { + ControlFlowTree desugared; + + DesugaredTree() { desugared = this.getDesugared() } + + final override predicate propagatesAbnormal(AstNode child) { + desugared.propagatesAbnormal(child) + } + + final override predicate first(AstNode first) { desugared.first(first) } + + final override predicate last(AstNode last, Completion c) { desugared.last(last, c) } + + final override predicate succ(AstNode pred, AstNode succ, Completion c) { none() } + } + private class DoBlockTree extends BodyStmtPostOrderTree, DoBlock { /** Gets the `i`th child in the body of this block. */ final override AstNode getBodyChild(int i, boolean rescuable) { diff --git a/ql/src/codeql_ruby/printAst.qll b/ql/src/codeql_ruby/printAst.qll index 2737e456251..f5e883e7996 100644 --- a/ql/src/codeql_ruby/printAst.qll +++ b/ql/src/codeql_ruby/printAst.qll @@ -8,6 +8,13 @@ import AST +/** Holds if `n` appears in the desugaring of some other node. */ +predicate isDesugared(AstNode n) { + n = any(AstNode sugar).getDesugared() + or + isDesugared(n.getParent()) +} + /** * The query can extend this class to control which nodes are printed. */ @@ -17,7 +24,19 @@ class PrintAstConfiguration extends string { /** * Holds if the given node should be printed. */ - predicate shouldPrintNode(AstNode n) { any() } + predicate shouldPrintNode(AstNode n) { + not isDesugared(n) + or + not n.isSynthesized() + or + n.isSynthesized() and + not n = any(AstNode sugar).getDesugared() and + exists(AstNode parent | + parent = n.getParent() and + not parent.isSynthesized() and + not n = parent.getDesugared() + ) + } } /** @@ -32,12 +51,11 @@ class PrintAstNode extends AstNode { result = any(int i | this = - rank[i](AstNode p | - | - p - order by - p.getLocation().getFile().getBaseName(), p.getLocation().getFile().getAbsolutePath(), - p.getLocation().getStartLine(), p.getLocation().getStartColumn() + rank[i](AstNode p, Location l, File f | + l = p.getLocation() and + f = l.getFile() + | + p order by f.getBaseName(), f.getAbsolutePath(), l.getStartLine(), l.getStartColumn() ) ).toString() } @@ -75,10 +93,10 @@ query predicate nodes(PrintAstNode node, string key, string value) { query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) { source.shouldPrint() and target.shouldPrint() and - target = source.getAChild() and + target = source.getChild(_) and ( key = "semmle.label" and - value = concat(string name | source.getChild(name) = target | name, "/") + value = strictconcat(string name | source.getChild(name) = target | name, "/") or key = "semmle.order" and value = target.getProperty("semmle.order") diff --git a/ql/test/library-tests/ast/Ast.ql b/ql/test/library-tests/ast/Ast.ql index 4cd412f83a0..babafaac548 100644 --- a/ql/test/library-tests/ast/Ast.ql +++ b/ql/test/library-tests/ast/Ast.ql @@ -1,6 +1,5 @@ /** * @kind graph - * @id rb/test/print-ast */ import codeql_ruby.printAst diff --git a/ql/test/library-tests/ast/AstDesugar.expected b/ql/test/library-tests/ast/AstDesugar.expected new file mode 100644 index 00000000000..6d3ce654d19 --- /dev/null +++ b/ql/test/library-tests/ast/AstDesugar.expected @@ -0,0 +1,180 @@ +calls/calls.rb: +# 66| [AssignExpr] ... = ... +# 66| getAnOperand/getLeftOperand: [LocalVariableAccess] var1 +# 66| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 66| getAnOperand/getLeftOperand: [LocalVariableAccess] var1 +# 66| getAnOperand/getRightOperand: [MethodCall] call to bar +# 66| getReceiver: [Self] self +# 67| [AssignExpr] ... = ... +# 67| getAnOperand/getLeftOperand: [LocalVariableAccess] var1 +# 67| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 67| getAnOperand/getLeftOperand: [LocalVariableAccess] var1 +# 67| getAnOperand/getRightOperand: [MethodCall] call to bar +# 67| getReceiver: [ConstantReadAccess] X +control/loops.rb: +# 10| [AssignExpr] ... = ... +# 10| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 10| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 10| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 10| getAnOperand/getRightOperand: [LocalVariableAccess] n +# 17| [AssignExpr] ... = ... +# 17| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 17| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 17| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 17| getAnOperand/getRightOperand: [LocalVariableAccess] n +# 18| [AssignExpr] ... = ... +# 18| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 18| getAnOperand/getRightOperand: [SubExpr] ... - ... +# 18| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 18| getAnOperand/getRightOperand: [LocalVariableAccess] n +# 23| [AssignExpr] ... = ... +# 23| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 23| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 23| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 23| getAnOperand/getRightOperand: [LocalVariableAccess] value +# 24| [AssignExpr] ... = ... +# 24| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 24| getAnOperand/getRightOperand: [MulExpr] ... * ... +# 24| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 24| getAnOperand/getRightOperand: [LocalVariableAccess] value +# 29| [AssignExpr] ... = ... +# 29| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 29| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 29| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 29| getAnOperand/getRightOperand: [LocalVariableAccess] value +# 30| [AssignExpr] ... = ... +# 30| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 30| getAnOperand/getRightOperand: [DivExpr] ... / ... +# 30| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 30| getAnOperand/getRightOperand: [LocalVariableAccess] value +# 36| [AssignExpr] ... = ... +# 36| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 36| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 36| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 36| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 37| [AssignExpr] ... = ... +# 37| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 37| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 37| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 37| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 43| [AssignExpr] ... = ... +# 43| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 43| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 43| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 43| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 44| [AssignExpr] ... = ... +# 44| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 44| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 44| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 44| getAnOperand/getRightOperand: [IntegerLiteral] 2 +# 48| [AssignExpr] ... = ... +# 48| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 48| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 48| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 48| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 52| [AssignExpr] ... = ... +# 52| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 52| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 52| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 52| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 53| [AssignExpr] ... = ... +# 53| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 53| getAnOperand/getRightOperand: [SubExpr] ... - ... +# 53| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 53| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 58| [AssignExpr] ... = ... +# 58| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 58| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 58| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 58| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 59| [AssignExpr] ... = ... +# 59| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 59| getAnOperand/getRightOperand: [SubExpr] ... - ... +# 59| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 59| getAnOperand/getRightOperand: [IntegerLiteral] 4 +# 63| [AssignExpr] ... = ... +# 63| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 63| getAnOperand/getRightOperand: [SubExpr] ... - ... +# 63| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 63| getAnOperand/getRightOperand: [IntegerLiteral] 1 +operations/operations.rb: +# 68| [AssignExpr] ... = ... +# 68| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 68| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 68| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 68| getAnOperand/getRightOperand: [IntegerLiteral] 128 +# 69| [AssignExpr] ... = ... +# 69| getAnOperand/getLeftOperand: [LocalVariableAccess] y +# 69| getAnOperand/getRightOperand: [SubExpr] ... - ... +# 69| getAnOperand/getLeftOperand: [LocalVariableAccess] y +# 69| getAnOperand/getRightOperand: [IntegerLiteral] 32 +# 70| [AssignExpr] ... = ... +# 70| getAnOperand/getLeftOperand: [LocalVariableAccess] a +# 70| getAnOperand/getRightOperand: [MulExpr] ... * ... +# 70| getAnOperand/getLeftOperand: [LocalVariableAccess] a +# 70| getAnOperand/getRightOperand: [IntegerLiteral] 12 +# 71| [AssignExpr] ... = ... +# 71| getAnOperand/getLeftOperand: [LocalVariableAccess] b +# 71| getAnOperand/getRightOperand: [DivExpr] ... / ... +# 71| getAnOperand/getLeftOperand: [LocalVariableAccess] b +# 71| getAnOperand/getRightOperand: [IntegerLiteral] 4 +# 72| [AssignExpr] ... = ... +# 72| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 72| getAnOperand/getRightOperand: [ModuloExpr] ... % ... +# 72| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 72| getAnOperand/getRightOperand: [IntegerLiteral] 2 +# 73| [AssignExpr] ... = ... +# 73| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 73| getAnOperand/getRightOperand: [ExponentExpr] ... ** ... +# 73| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 73| getAnOperand/getRightOperand: [LocalVariableAccess] bar +# 76| [AssignExpr] ... = ... +# 76| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 76| getAnOperand/getRightOperand: [LogicalAndExpr] ... && ... +# 76| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 76| getAnOperand/getRightOperand: [LocalVariableAccess] y +# 77| [AssignExpr] ... = ... +# 77| getAnOperand/getLeftOperand: [LocalVariableAccess] a +# 77| getAnOperand/getRightOperand: [LogicalOrExpr] ... || ... +# 77| getAnOperand/getLeftOperand: [LocalVariableAccess] a +# 77| getAnOperand/getRightOperand: [LocalVariableAccess] b +# 80| [AssignExpr] ... = ... +# 80| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 80| getAnOperand/getRightOperand: [LShiftExpr] ... << ... +# 80| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 80| getAnOperand/getRightOperand: [IntegerLiteral] 2 +# 81| [AssignExpr] ... = ... +# 81| getAnOperand/getLeftOperand: [LocalVariableAccess] y +# 81| getAnOperand/getRightOperand: [RShiftExpr] ... >> ... +# 81| getAnOperand/getLeftOperand: [LocalVariableAccess] y +# 81| getAnOperand/getRightOperand: [IntegerLiteral] 3 +# 82| [AssignExpr] ... = ... +# 82| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 82| getAnOperand/getRightOperand: [BitwiseAndExpr] ... & ... +# 82| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 82| getAnOperand/getRightOperand: [LocalVariableAccess] mask +# 83| [AssignExpr] ... = ... +# 83| getAnOperand/getLeftOperand: [LocalVariableAccess] bar +# 83| getAnOperand/getRightOperand: [BitwiseOrExpr] ... | ... +# 83| getAnOperand/getLeftOperand: [LocalVariableAccess] bar +# 83| getAnOperand/getRightOperand: [IntegerLiteral] 0x01 +# 84| [AssignExpr] ... = ... +# 84| getAnOperand/getLeftOperand: [LocalVariableAccess] baz +# 84| getAnOperand/getRightOperand: [BitwiseXorExpr] ... ^ ... +# 84| getAnOperand/getLeftOperand: [LocalVariableAccess] baz +# 84| getAnOperand/getRightOperand: [LocalVariableAccess] qux +# 88| [AssignExpr] ... = ... +# 88| getAnOperand/getLeftOperand: [InstanceVariableAccess] @x +# 88| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 88| getAnOperand/getLeftOperand: [InstanceVariableAccess] @x +# 88| getAnOperand/getRightOperand: [IntegerLiteral] 2 +# 91| [AssignExpr] ... = ... +# 91| getAnOperand/getLeftOperand: [ClassVariableAccess] @@y +# 91| getAnOperand/getRightOperand: [DivExpr] ... / ... +# 91| getAnOperand/getLeftOperand: [ClassVariableAccess] @@y +# 91| getAnOperand/getRightOperand: [IntegerLiteral] 4 +# 95| [AssignExpr] ... = ... +# 95| getAnOperand/getLeftOperand: [GlobalVariableAccess] $global_var +# 95| getAnOperand/getRightOperand: [MulExpr] ... * ... +# 95| getAnOperand/getLeftOperand: [GlobalVariableAccess] $global_var +# 95| getAnOperand/getRightOperand: [IntegerLiteral] 6 diff --git a/ql/test/library-tests/ast/AstDesugar.ql b/ql/test/library-tests/ast/AstDesugar.ql new file mode 100644 index 00000000000..bad92ac1c35 --- /dev/null +++ b/ql/test/library-tests/ast/AstDesugar.ql @@ -0,0 +1,9 @@ +/** + * @kind graph + */ + +import codeql_ruby.printAst + +class DesugarPrintAstConfiguration extends PrintAstConfiguration { + override predicate shouldPrintNode(AstNode n) { isDesugared(n) } +} diff --git a/ql/test/library-tests/ast/operations/assignment.expected b/ql/test/library-tests/ast/operations/assignment.expected index 454f86743ba..e1a72d00e19 100644 --- a/ql/test/library-tests/ast/operations/assignment.expected +++ b/ql/test/library-tests/ast/operations/assignment.expected @@ -18,24 +18,40 @@ assignments | operations.rb:19:1:19:5 | ... = ... | = | operations.rb:19:1:19:1 | y | operations.rb:19:5:19:5 | 0 | AssignExpr | | operations.rb:20:1:20:5 | ... = ... | = | operations.rb:20:1:20:1 | z | operations.rb:20:5:20:5 | 0 | AssignExpr | | operations.rb:68:1:68:8 | ... += ... | += | operations.rb:68:1:68:1 | x | operations.rb:68:6:68:8 | 128 | AssignAddExpr | +| operations.rb:68:1:68:8 | ... = ... | = | operations.rb:68:1:68:1 | x | operations.rb:68:1:68:8 | ... + ... | AssignExpr | | operations.rb:69:1:69:7 | ... -= ... | -= | operations.rb:69:1:69:1 | y | operations.rb:69:6:69:7 | 32 | AssignSubExpr | +| operations.rb:69:1:69:7 | ... = ... | = | operations.rb:69:1:69:1 | y | operations.rb:69:1:69:7 | ... - ... | AssignExpr | | operations.rb:70:1:70:7 | ... *= ... | *= | operations.rb:70:1:70:1 | a | operations.rb:70:6:70:7 | 12 | AssignMulExpr | +| operations.rb:70:1:70:7 | ... = ... | = | operations.rb:70:1:70:1 | a | operations.rb:70:1:70:7 | ... * ... | AssignExpr | | operations.rb:71:1:71:6 | ... /= ... | /= | operations.rb:71:1:71:1 | b | operations.rb:71:6:71:6 | 4 | AssignDivExpr | +| operations.rb:71:1:71:6 | ... = ... | = | operations.rb:71:1:71:1 | b | operations.rb:71:1:71:6 | ... / ... | AssignExpr | | operations.rb:72:1:72:6 | ... %= ... | %= | operations.rb:72:1:72:1 | z | operations.rb:72:6:72:6 | 2 | AssignModuloExpr | +| operations.rb:72:1:72:6 | ... = ... | = | operations.rb:72:1:72:1 | z | operations.rb:72:1:72:6 | ... % ... | AssignExpr | | operations.rb:73:1:73:11 | ... **= ... | **= | operations.rb:73:1:73:3 | foo | operations.rb:73:9:73:11 | bar | AssignExponentExpr | +| operations.rb:73:1:73:11 | ... = ... | = | operations.rb:73:1:73:3 | foo | operations.rb:73:1:73:11 | ... ** ... | AssignExpr | | operations.rb:76:2:76:8 | ... &&= ... | &&= | operations.rb:76:2:76:2 | x | operations.rb:76:8:76:8 | y | AssignLogicalAndExpr | +| operations.rb:76:2:76:8 | ... = ... | = | operations.rb:76:2:76:2 | x | operations.rb:76:2:76:8 | ... && ... | AssignExpr | +| operations.rb:77:2:77:8 | ... = ... | = | operations.rb:77:2:77:2 | a | operations.rb:77:2:77:8 | ... \|\| ... | AssignExpr | | operations.rb:77:2:77:8 | ... \|\|= ... | \|\|= | operations.rb:77:2:77:2 | a | operations.rb:77:8:77:8 | b | AssignLogicalOrExpr | | operations.rb:80:2:80:8 | ... <<= ... | <<= | operations.rb:80:2:80:2 | x | operations.rb:80:8:80:8 | 2 | AssignLShiftExpr | +| operations.rb:80:2:80:8 | ... = ... | = | operations.rb:80:2:80:2 | x | operations.rb:80:2:80:8 | ... << ... | AssignExpr | +| operations.rb:81:2:81:8 | ... = ... | = | operations.rb:81:2:81:2 | y | operations.rb:81:2:81:8 | ... >> ... | AssignExpr | | operations.rb:81:2:81:8 | ... >>= ... | >>= | operations.rb:81:2:81:2 | y | operations.rb:81:8:81:8 | 3 | AssignRShiftExpr | | operations.rb:82:2:82:12 | ... &= ... | &= | operations.rb:82:2:82:4 | foo | operations.rb:82:9:82:12 | mask | AssignBitwiseAndExpr | +| operations.rb:82:2:82:12 | ... = ... | = | operations.rb:82:2:82:4 | foo | operations.rb:82:2:82:12 | ... & ... | AssignExpr | +| operations.rb:83:2:83:12 | ... = ... | = | operations.rb:83:2:83:4 | bar | operations.rb:83:2:83:12 | ... \| ... | AssignExpr | | operations.rb:83:2:83:12 | ... \|= ... | \|= | operations.rb:83:2:83:4 | bar | operations.rb:83:9:83:12 | 0x01 | AssignBitwiseOrExpr | +| operations.rb:84:2:84:11 | ... = ... | = | operations.rb:84:2:84:4 | baz | operations.rb:84:2:84:11 | ... ^ ... | AssignExpr | | operations.rb:84:2:84:11 | ... ^= ... | ^= | operations.rb:84:2:84:4 | baz | operations.rb:84:9:84:11 | qux | AssignBitwiseXorExpr | | operations.rb:87:3:87:8 | ... = ... | = | operations.rb:87:3:87:4 | @x | operations.rb:87:8:87:8 | 1 | AssignExpr | | operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:3:88:4 | @x | operations.rb:88:9:88:9 | 2 | AssignAddExpr | +| operations.rb:88:3:88:9 | ... = ... | = | operations.rb:88:3:88:4 | @x | operations.rb:88:3:88:9 | ... + ... | AssignExpr | | operations.rb:90:3:90:9 | ... = ... | = | operations.rb:90:3:90:5 | @@y | operations.rb:90:9:90:9 | 3 | AssignExpr | | operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:3:91:5 | @@y | operations.rb:91:10:91:10 | 4 | AssignDivExpr | +| operations.rb:91:3:91:10 | ... = ... | = | operations.rb:91:3:91:5 | @@y | operations.rb:91:3:91:10 | ... / ... | AssignExpr | | operations.rb:94:1:94:15 | ... = ... | = | operations.rb:94:1:94:11 | $global_var | operations.rb:94:15:94:15 | 5 | AssignExpr | | operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:1:95:11 | $global_var | operations.rb:95:16:95:16 | 6 | AssignMulExpr | +| operations.rb:95:1:95:16 | ... = ... | = | operations.rb:95:1:95:11 | $global_var | operations.rb:95:1:95:16 | ... * ... | AssignExpr | assignOperations | operations.rb:68:1:68:8 | ... += ... | += | operations.rb:68:1:68:1 | x | operations.rb:68:6:68:8 | 128 | AssignAddExpr | | operations.rb:69:1:69:7 | ... -= ... | -= | operations.rb:69:1:69:1 | y | operations.rb:69:6:69:7 | 32 | AssignSubExpr | diff --git a/ql/test/library-tests/ast/operations/binary.expected b/ql/test/library-tests/ast/operations/binary.expected index e59833bd54a..998d2cc343f 100644 --- a/ql/test/library-tests/ast/operations/binary.expected +++ b/ql/test/library-tests/ast/operations/binary.expected @@ -24,6 +24,22 @@ binaryOperations | operations.rb:63:1:63:7 | ... <=> ... | <=> | operations.rb:63:1:63:1 | a | operations.rb:63:7:63:7 | b | SpaceshipExpr | | operations.rb:64:1:64:15 | ... =~ ... | =~ | operations.rb:64:1:64:4 | name | operations.rb:64:9:64:15 | /foo.*/ | RegexMatchExpr | | operations.rb:65:1:65:17 | ... !~ ... | !~ | operations.rb:65:1:65:6 | handle | operations.rb:65:11:65:17 | /.*bar/ | NoRegexMatchExpr | +| operations.rb:68:1:68:8 | ... + ... | + | operations.rb:68:1:68:8 | x | operations.rb:68:6:68:8 | 128 | AddExpr | +| operations.rb:69:1:69:7 | ... - ... | - | operations.rb:69:1:69:7 | y | operations.rb:69:6:69:7 | 32 | SubExpr | +| operations.rb:70:1:70:7 | ... * ... | * | operations.rb:70:1:70:7 | a | operations.rb:70:6:70:7 | 12 | MulExpr | +| operations.rb:71:1:71:6 | ... / ... | / | operations.rb:71:1:71:6 | b | operations.rb:71:6:71:6 | 4 | DivExpr | +| operations.rb:72:1:72:6 | ... % ... | % | operations.rb:72:1:72:6 | z | operations.rb:72:6:72:6 | 2 | ModuloExpr | +| operations.rb:73:1:73:11 | ... ** ... | ** | operations.rb:73:1:73:11 | foo | operations.rb:73:9:73:11 | bar | ExponentExpr | +| operations.rb:76:2:76:8 | ... && ... | && | operations.rb:76:2:76:8 | x | operations.rb:76:8:76:8 | y | LogicalAndExpr | +| operations.rb:77:2:77:8 | ... \|\| ... | \|\| | operations.rb:77:2:77:8 | a | operations.rb:77:8:77:8 | b | LogicalOrExpr | +| operations.rb:80:2:80:8 | ... << ... | << | operations.rb:80:2:80:8 | x | operations.rb:80:8:80:8 | 2 | LShiftExpr | +| operations.rb:81:2:81:8 | ... >> ... | >> | operations.rb:81:2:81:8 | y | operations.rb:81:8:81:8 | 3 | RShiftExpr | +| operations.rb:82:2:82:12 | ... & ... | & | operations.rb:82:2:82:12 | foo | operations.rb:82:9:82:12 | mask | BitwiseAndExpr | +| operations.rb:83:2:83:12 | ... \| ... | \| | operations.rb:83:2:83:12 | bar | operations.rb:83:9:83:12 | 0x01 | BitwiseOrExpr | +| operations.rb:84:2:84:11 | ... ^ ... | ^ | operations.rb:84:2:84:11 | baz | operations.rb:84:9:84:11 | qux | BitwiseXorExpr | +| operations.rb:88:3:88:9 | ... + ... | + | operations.rb:88:3:88:9 | @x | operations.rb:88:9:88:9 | 2 | AddExpr | +| operations.rb:91:3:91:10 | ... / ... | / | operations.rb:91:3:91:10 | @@y | operations.rb:91:10:91:10 | 4 | DivExpr | +| operations.rb:95:1:95:16 | ... * ... | * | operations.rb:95:1:95:16 | $global_var | operations.rb:95:16:95:16 | 6 | MulExpr | binaryArithmeticOperations | operations.rb:31:1:31:7 | ... + ... | + | operations.rb:31:1:31:1 | w | operations.rb:31:5:31:7 | 234 | AddExpr | | operations.rb:32:1:32:6 | ... - ... | - | operations.rb:32:1:32:1 | x | operations.rb:32:5:32:6 | 17 | SubExpr | @@ -31,17 +47,33 @@ binaryArithmeticOperations | operations.rb:34:1:34:5 | ... / ... | / | operations.rb:34:1:34:1 | z | operations.rb:34:5:34:5 | 2 | DivExpr | | operations.rb:35:1:35:7 | ... % ... | % | operations.rb:35:1:35:3 | num | operations.rb:35:7:35:7 | 2 | ModuloExpr | | operations.rb:36:1:36:13 | ... ** ... | ** | operations.rb:36:1:36:4 | base | operations.rb:36:9:36:13 | power | ExponentExpr | +| operations.rb:68:1:68:8 | ... + ... | + | operations.rb:68:1:68:8 | x | operations.rb:68:6:68:8 | 128 | AddExpr | +| operations.rb:69:1:69:7 | ... - ... | - | operations.rb:69:1:69:7 | y | operations.rb:69:6:69:7 | 32 | SubExpr | +| operations.rb:70:1:70:7 | ... * ... | * | operations.rb:70:1:70:7 | a | operations.rb:70:6:70:7 | 12 | MulExpr | +| operations.rb:71:1:71:6 | ... / ... | / | operations.rb:71:1:71:6 | b | operations.rb:71:6:71:6 | 4 | DivExpr | +| operations.rb:72:1:72:6 | ... % ... | % | operations.rb:72:1:72:6 | z | operations.rb:72:6:72:6 | 2 | ModuloExpr | +| operations.rb:73:1:73:11 | ... ** ... | ** | operations.rb:73:1:73:11 | foo | operations.rb:73:9:73:11 | bar | ExponentExpr | +| operations.rb:88:3:88:9 | ... + ... | + | operations.rb:88:3:88:9 | @x | operations.rb:88:9:88:9 | 2 | AddExpr | +| operations.rb:91:3:91:10 | ... / ... | / | operations.rb:91:3:91:10 | @@y | operations.rb:91:10:91:10 | 4 | DivExpr | +| operations.rb:95:1:95:16 | ... * ... | * | operations.rb:95:1:95:16 | $global_var | operations.rb:95:16:95:16 | 6 | MulExpr | binaryLogicalOperations | operations.rb:39:1:39:10 | ... && ... | && | operations.rb:39:1:39:3 | foo | operations.rb:39:8:39:10 | bar | LogicalAndExpr | | operations.rb:40:1:40:11 | ... and ... | and | operations.rb:40:1:40:3 | baz | operations.rb:40:9:40:11 | qux | LogicalAndExpr | | operations.rb:41:1:41:6 | ... or ... | or | operations.rb:41:1:41:1 | a | operations.rb:41:6:41:6 | b | LogicalOrExpr | | operations.rb:42:1:42:6 | ... \|\| ... | \|\| | operations.rb:42:1:42:1 | x | operations.rb:42:6:42:6 | y | LogicalOrExpr | +| operations.rb:76:2:76:8 | ... && ... | && | operations.rb:76:2:76:8 | x | operations.rb:76:8:76:8 | y | LogicalAndExpr | +| operations.rb:77:2:77:8 | ... \|\| ... | \|\| | operations.rb:77:2:77:8 | a | operations.rb:77:8:77:8 | b | LogicalOrExpr | binaryBitwiseOperations | operations.rb:45:1:45:6 | ... << ... | << | operations.rb:45:1:45:1 | x | operations.rb:45:6:45:6 | 3 | LShiftExpr | | operations.rb:46:1:46:7 | ... >> ... | >> | operations.rb:46:1:46:1 | y | operations.rb:46:6:46:7 | 16 | RShiftExpr | | operations.rb:47:1:47:10 | ... & ... | & | operations.rb:47:1:47:3 | foo | operations.rb:47:7:47:10 | 0xff | BitwiseAndExpr | | operations.rb:48:1:48:10 | ... \| ... | \| | operations.rb:48:1:48:3 | bar | operations.rb:48:7:48:10 | 0x02 | BitwiseOrExpr | | operations.rb:49:1:49:9 | ... ^ ... | ^ | operations.rb:49:1:49:3 | baz | operations.rb:49:7:49:9 | qux | BitwiseXorExpr | +| operations.rb:80:2:80:8 | ... << ... | << | operations.rb:80:2:80:8 | x | operations.rb:80:8:80:8 | 2 | LShiftExpr | +| operations.rb:81:2:81:8 | ... >> ... | >> | operations.rb:81:2:81:8 | y | operations.rb:81:8:81:8 | 3 | RShiftExpr | +| operations.rb:82:2:82:12 | ... & ... | & | operations.rb:82:2:82:12 | foo | operations.rb:82:9:82:12 | mask | BitwiseAndExpr | +| operations.rb:83:2:83:12 | ... \| ... | \| | operations.rb:83:2:83:12 | bar | operations.rb:83:9:83:12 | 0x01 | BitwiseOrExpr | +| operations.rb:84:2:84:11 | ... ^ ... | ^ | operations.rb:84:2:84:11 | baz | operations.rb:84:9:84:11 | qux | BitwiseXorExpr | comparisonOperations | operations.rb:52:1:52:6 | ... == ... | == | operations.rb:52:1:52:1 | x | operations.rb:52:6:52:6 | y | EqExpr | | operations.rb:53:1:53:8 | ... != ... | != | operations.rb:53:1:53:1 | a | operations.rb:53:6:53:8 | 123 | NEExpr | diff --git a/ql/test/library-tests/ast/operations/operation.expected b/ql/test/library-tests/ast/operations/operation.expected index 7f4d25068eb..86818353455 100644 --- a/ql/test/library-tests/ast/operations/operation.expected +++ b/ql/test/library-tests/ast/operations/operation.expected @@ -90,41 +90,105 @@ | operations.rb:64:1:64:15 | ... =~ ... | =~ | operations.rb:64:9:64:15 | /foo.*/ | RegexMatchExpr | | operations.rb:65:1:65:17 | ... !~ ... | !~ | operations.rb:65:1:65:6 | handle | NoRegexMatchExpr | | operations.rb:65:1:65:17 | ... !~ ... | !~ | operations.rb:65:11:65:17 | /.*bar/ | NoRegexMatchExpr | +| operations.rb:68:1:68:8 | ... + ... | + | operations.rb:68:1:68:8 | x | AddExpr | +| operations.rb:68:1:68:8 | ... + ... | + | operations.rb:68:6:68:8 | 128 | AddExpr | | operations.rb:68:1:68:8 | ... += ... | += | operations.rb:68:1:68:1 | x | AssignAddExpr | | operations.rb:68:1:68:8 | ... += ... | += | operations.rb:68:6:68:8 | 128 | AssignAddExpr | +| operations.rb:68:1:68:8 | ... = ... | = | operations.rb:68:1:68:1 | x | AssignExpr | +| operations.rb:68:1:68:8 | ... = ... | = | operations.rb:68:1:68:8 | ... + ... | AssignExpr | +| operations.rb:69:1:69:7 | ... - ... | - | operations.rb:69:1:69:7 | y | SubExpr | +| operations.rb:69:1:69:7 | ... - ... | - | operations.rb:69:6:69:7 | 32 | SubExpr | | operations.rb:69:1:69:7 | ... -= ... | -= | operations.rb:69:1:69:1 | y | AssignSubExpr | | operations.rb:69:1:69:7 | ... -= ... | -= | operations.rb:69:6:69:7 | 32 | AssignSubExpr | +| operations.rb:69:1:69:7 | ... = ... | = | operations.rb:69:1:69:1 | y | AssignExpr | +| operations.rb:69:1:69:7 | ... = ... | = | operations.rb:69:1:69:7 | ... - ... | AssignExpr | +| operations.rb:70:1:70:7 | ... * ... | * | operations.rb:70:1:70:7 | a | MulExpr | +| operations.rb:70:1:70:7 | ... * ... | * | operations.rb:70:6:70:7 | 12 | MulExpr | | operations.rb:70:1:70:7 | ... *= ... | *= | operations.rb:70:1:70:1 | a | AssignMulExpr | | operations.rb:70:1:70:7 | ... *= ... | *= | operations.rb:70:6:70:7 | 12 | AssignMulExpr | +| operations.rb:70:1:70:7 | ... = ... | = | operations.rb:70:1:70:1 | a | AssignExpr | +| operations.rb:70:1:70:7 | ... = ... | = | operations.rb:70:1:70:7 | ... * ... | AssignExpr | +| operations.rb:71:1:71:6 | ... / ... | / | operations.rb:71:1:71:6 | b | DivExpr | +| operations.rb:71:1:71:6 | ... / ... | / | operations.rb:71:6:71:6 | 4 | DivExpr | | operations.rb:71:1:71:6 | ... /= ... | /= | operations.rb:71:1:71:1 | b | AssignDivExpr | | operations.rb:71:1:71:6 | ... /= ... | /= | operations.rb:71:6:71:6 | 4 | AssignDivExpr | +| operations.rb:71:1:71:6 | ... = ... | = | operations.rb:71:1:71:1 | b | AssignExpr | +| operations.rb:71:1:71:6 | ... = ... | = | operations.rb:71:1:71:6 | ... / ... | AssignExpr | +| operations.rb:72:1:72:6 | ... % ... | % | operations.rb:72:1:72:6 | z | ModuloExpr | +| operations.rb:72:1:72:6 | ... % ... | % | operations.rb:72:6:72:6 | 2 | ModuloExpr | | operations.rb:72:1:72:6 | ... %= ... | %= | operations.rb:72:1:72:1 | z | AssignModuloExpr | | operations.rb:72:1:72:6 | ... %= ... | %= | operations.rb:72:6:72:6 | 2 | AssignModuloExpr | +| operations.rb:72:1:72:6 | ... = ... | = | operations.rb:72:1:72:1 | z | AssignExpr | +| operations.rb:72:1:72:6 | ... = ... | = | operations.rb:72:1:72:6 | ... % ... | AssignExpr | +| operations.rb:73:1:73:11 | ... ** ... | ** | operations.rb:73:1:73:11 | foo | ExponentExpr | +| operations.rb:73:1:73:11 | ... ** ... | ** | operations.rb:73:9:73:11 | bar | ExponentExpr | | operations.rb:73:1:73:11 | ... **= ... | **= | operations.rb:73:1:73:3 | foo | AssignExponentExpr | | operations.rb:73:1:73:11 | ... **= ... | **= | operations.rb:73:9:73:11 | bar | AssignExponentExpr | +| operations.rb:73:1:73:11 | ... = ... | = | operations.rb:73:1:73:3 | foo | AssignExpr | +| operations.rb:73:1:73:11 | ... = ... | = | operations.rb:73:1:73:11 | ... ** ... | AssignExpr | +| operations.rb:76:2:76:8 | ... && ... | && | operations.rb:76:2:76:8 | x | LogicalAndExpr | +| operations.rb:76:2:76:8 | ... && ... | && | operations.rb:76:8:76:8 | y | LogicalAndExpr | | operations.rb:76:2:76:8 | ... &&= ... | &&= | operations.rb:76:2:76:2 | x | AssignLogicalAndExpr | | operations.rb:76:2:76:8 | ... &&= ... | &&= | operations.rb:76:8:76:8 | y | AssignLogicalAndExpr | +| operations.rb:76:2:76:8 | ... = ... | = | operations.rb:76:2:76:2 | x | AssignExpr | +| operations.rb:76:2:76:8 | ... = ... | = | operations.rb:76:2:76:8 | ... && ... | AssignExpr | +| operations.rb:77:2:77:8 | ... = ... | = | operations.rb:77:2:77:2 | a | AssignExpr | +| operations.rb:77:2:77:8 | ... = ... | = | operations.rb:77:2:77:8 | ... \|\| ... | AssignExpr | +| operations.rb:77:2:77:8 | ... \|\| ... | \|\| | operations.rb:77:2:77:8 | a | LogicalOrExpr | +| operations.rb:77:2:77:8 | ... \|\| ... | \|\| | operations.rb:77:8:77:8 | b | LogicalOrExpr | | operations.rb:77:2:77:8 | ... \|\|= ... | \|\|= | operations.rb:77:2:77:2 | a | AssignLogicalOrExpr | | operations.rb:77:2:77:8 | ... \|\|= ... | \|\|= | operations.rb:77:8:77:8 | b | AssignLogicalOrExpr | +| operations.rb:80:2:80:8 | ... << ... | << | operations.rb:80:2:80:8 | x | LShiftExpr | +| operations.rb:80:2:80:8 | ... << ... | << | operations.rb:80:8:80:8 | 2 | LShiftExpr | | operations.rb:80:2:80:8 | ... <<= ... | <<= | operations.rb:80:2:80:2 | x | AssignLShiftExpr | | operations.rb:80:2:80:8 | ... <<= ... | <<= | operations.rb:80:8:80:8 | 2 | AssignLShiftExpr | +| operations.rb:80:2:80:8 | ... = ... | = | operations.rb:80:2:80:2 | x | AssignExpr | +| operations.rb:80:2:80:8 | ... = ... | = | operations.rb:80:2:80:8 | ... << ... | AssignExpr | +| operations.rb:81:2:81:8 | ... = ... | = | operations.rb:81:2:81:2 | y | AssignExpr | +| operations.rb:81:2:81:8 | ... = ... | = | operations.rb:81:2:81:8 | ... >> ... | AssignExpr | +| operations.rb:81:2:81:8 | ... >> ... | >> | operations.rb:81:2:81:8 | y | RShiftExpr | +| operations.rb:81:2:81:8 | ... >> ... | >> | operations.rb:81:8:81:8 | 3 | RShiftExpr | | operations.rb:81:2:81:8 | ... >>= ... | >>= | operations.rb:81:2:81:2 | y | AssignRShiftExpr | | operations.rb:81:2:81:8 | ... >>= ... | >>= | operations.rb:81:8:81:8 | 3 | AssignRShiftExpr | +| operations.rb:82:2:82:12 | ... & ... | & | operations.rb:82:2:82:12 | foo | BitwiseAndExpr | +| operations.rb:82:2:82:12 | ... & ... | & | operations.rb:82:9:82:12 | mask | BitwiseAndExpr | | operations.rb:82:2:82:12 | ... &= ... | &= | operations.rb:82:2:82:4 | foo | AssignBitwiseAndExpr | | operations.rb:82:2:82:12 | ... &= ... | &= | operations.rb:82:9:82:12 | mask | AssignBitwiseAndExpr | +| operations.rb:82:2:82:12 | ... = ... | = | operations.rb:82:2:82:4 | foo | AssignExpr | +| operations.rb:82:2:82:12 | ... = ... | = | operations.rb:82:2:82:12 | ... & ... | AssignExpr | +| operations.rb:83:2:83:12 | ... = ... | = | operations.rb:83:2:83:4 | bar | AssignExpr | +| operations.rb:83:2:83:12 | ... = ... | = | operations.rb:83:2:83:12 | ... \| ... | AssignExpr | +| operations.rb:83:2:83:12 | ... \| ... | \| | operations.rb:83:2:83:12 | bar | BitwiseOrExpr | +| operations.rb:83:2:83:12 | ... \| ... | \| | operations.rb:83:9:83:12 | 0x01 | BitwiseOrExpr | | operations.rb:83:2:83:12 | ... \|= ... | \|= | operations.rb:83:2:83:4 | bar | AssignBitwiseOrExpr | | operations.rb:83:2:83:12 | ... \|= ... | \|= | operations.rb:83:9:83:12 | 0x01 | AssignBitwiseOrExpr | +| operations.rb:84:2:84:11 | ... = ... | = | operations.rb:84:2:84:4 | baz | AssignExpr | +| operations.rb:84:2:84:11 | ... = ... | = | operations.rb:84:2:84:11 | ... ^ ... | AssignExpr | +| operations.rb:84:2:84:11 | ... ^ ... | ^ | operations.rb:84:2:84:11 | baz | BitwiseXorExpr | +| operations.rb:84:2:84:11 | ... ^ ... | ^ | operations.rb:84:9:84:11 | qux | BitwiseXorExpr | | operations.rb:84:2:84:11 | ... ^= ... | ^= | operations.rb:84:2:84:4 | baz | AssignBitwiseXorExpr | | operations.rb:84:2:84:11 | ... ^= ... | ^= | operations.rb:84:9:84:11 | qux | AssignBitwiseXorExpr | | operations.rb:87:3:87:8 | ... = ... | = | operations.rb:87:3:87:4 | @x | AssignExpr | | operations.rb:87:3:87:8 | ... = ... | = | operations.rb:87:8:87:8 | 1 | AssignExpr | +| operations.rb:88:3:88:9 | ... + ... | + | operations.rb:88:3:88:9 | @x | AddExpr | +| operations.rb:88:3:88:9 | ... + ... | + | operations.rb:88:9:88:9 | 2 | AddExpr | | operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:3:88:4 | @x | AssignAddExpr | | operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:9:88:9 | 2 | AssignAddExpr | +| operations.rb:88:3:88:9 | ... = ... | = | operations.rb:88:3:88:4 | @x | AssignExpr | +| operations.rb:88:3:88:9 | ... = ... | = | operations.rb:88:3:88:9 | ... + ... | AssignExpr | | operations.rb:90:3:90:9 | ... = ... | = | operations.rb:90:3:90:5 | @@y | AssignExpr | | operations.rb:90:3:90:9 | ... = ... | = | operations.rb:90:9:90:9 | 3 | AssignExpr | +| operations.rb:91:3:91:10 | ... / ... | / | operations.rb:91:3:91:10 | @@y | DivExpr | +| operations.rb:91:3:91:10 | ... / ... | / | operations.rb:91:10:91:10 | 4 | DivExpr | | operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:3:91:5 | @@y | AssignDivExpr | | operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:10:91:10 | 4 | AssignDivExpr | +| operations.rb:91:3:91:10 | ... = ... | = | operations.rb:91:3:91:5 | @@y | AssignExpr | +| operations.rb:91:3:91:10 | ... = ... | = | operations.rb:91:3:91:10 | ... / ... | AssignExpr | | operations.rb:94:1:94:15 | ... = ... | = | operations.rb:94:1:94:11 | $global_var | AssignExpr | | operations.rb:94:1:94:15 | ... = ... | = | operations.rb:94:15:94:15 | 5 | AssignExpr | +| operations.rb:95:1:95:16 | ... * ... | * | operations.rb:95:1:95:16 | $global_var | MulExpr | +| operations.rb:95:1:95:16 | ... * ... | * | operations.rb:95:16:95:16 | 6 | MulExpr | | operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:1:95:11 | $global_var | AssignMulExpr | | operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:16:95:16 | 6 | AssignMulExpr | +| operations.rb:95:1:95:16 | ... = ... | = | operations.rb:95:1:95:11 | $global_var | AssignExpr | +| operations.rb:95:1:95:16 | ... = ... | = | operations.rb:95:1:95:16 | ... * ... | AssignExpr | diff --git a/ql/test/library-tests/controlflow/graph/Cfg.expected b/ql/test/library-tests/controlflow/graph/Cfg.expected index 84e66808854..416921e9866 100644 --- a/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -687,12 +687,12 @@ cfg.rb: # 35| false #-----| false -> if ... -# 39| self -#-----| -> 42 - # 39| call to puts #-----| -> case ... +# 39| self +#-----| -> 42 + # 39| 42 #-----| -> call to puts @@ -1444,14 +1444,20 @@ cfg.rb: # 124| 2 #-----| -> ... = ... -# 125| ... += ... +# 125| some +#-----| -> some + +# 125| ... = ... #-----| -> last +# 125| ... + ... +#-----| -> ... = ... + # 125| some #-----| -> 10 # 125| 10 -#-----| -> ... += ... +#-----| -> ... + ... # 126| ... = ... #-----| -> range @@ -1544,8 +1550,8 @@ cfg.rb: #-----| -> ... rescue ... # 136| ... / ... -#-----| raise -> self #-----| -> init +#-----| raise -> self # 136| 1 #-----| -> 0 @@ -1880,14 +1886,20 @@ cfg.rb: # 176| do ... #-----| -> x -# 176| ... += ... +# 176| x +#-----| -> x + +# 176| ... = ... #-----| -> self +# 176| ... + ... +#-----| -> ... = ... + # 176| x #-----| -> 10 # 176| 10 -#-----| -> ... += ... +#-----| -> ... + ... # 176| call to puts #-----| -> x @@ -1922,14 +1934,20 @@ cfg.rb: # 179| "hello" #-----| -> call to puts -# 179| ... += ... +# 179| i +#-----| -> i + +# 179| ... = ... #-----| -> ( ... ) +# 179| ... + ... +#-----| -> ... = ... + # 179| i #-----| -> 1 # 179| 1 -#-----| -> ... += ... +#-----| -> ... + ... # 179| ... == ... #-----| true -> ... until ... @@ -1966,14 +1984,20 @@ cfg.rb: # 182| do ... #-----| -> x -# 183| ... += ... +# 183| x #-----| -> x +# 183| ... = ... +#-----| -> x + +# 183| ... + ... +#-----| -> ... = ... + # 183| x #-----| -> 1 # 183| 1 -#-----| -> ... += ... +#-----| -> ... + ... # 184| if ... #-----| -> self @@ -2018,14 +2042,20 @@ cfg.rb: # 188| "hello" #-----| -> call to puts -# 188| ... -= ... +# 188| i +#-----| -> i + +# 188| ... = ... #-----| -> ( ... ) +# 188| ... - ... +#-----| -> ... = ... + # 188| i #-----| -> 1 # 188| 1 -#-----| -> ... -= ... +#-----| -> ... - ... # 188| ... != ... #-----| false -> ... while ... @@ -2106,14 +2136,20 @@ desugar.rb: # 1| x #-----| -> x -# 2| ... += ... +# 2| x +#-----| -> x + +# 2| ... = ... #-----| -> exit m1 (normal) +# 2| ... + ... +#-----| -> ... = ... + # 2| x #-----| -> 1 # 2| 1 -#-----| -> ... += ... +#-----| -> ... + ... # 5| enter m2 #-----| -> x @@ -2209,14 +2245,20 @@ desugar.rb: # 14| 1 #-----| -> ... = ... -# 15| ... += ... +# 15| @x +#-----| -> @x + +# 15| ... = ... #-----| -> @@y +# 15| ... + ... +#-----| -> ... = ... + # 15| @x #-----| -> 2 # 15| 2 -#-----| -> ... += ... +#-----| -> ... + ... # 17| ... = ... #-----| -> @@y @@ -2227,14 +2269,20 @@ desugar.rb: # 17| 3 #-----| -> ... = ... -# 18| ... /= ... +# 18| @@y +#-----| -> @@y + +# 18| ... = ... #-----| -> $global_var +# 18| ... / ... +#-----| -> ... = ... + # 18| @@y #-----| -> 4 # 18| 4 -#-----| -> ... /= ... +#-----| -> ... / ... # 21| ... = ... #-----| -> $global_var @@ -2245,14 +2293,20 @@ desugar.rb: # 21| 5 #-----| -> ... = ... -# 22| ... *= ... +# 22| $global_var +#-----| -> $global_var + +# 22| ... = ... #-----| -> exit desugar.rb (normal) +# 22| ... * ... +#-----| -> ... = ... + # 22| $global_var #-----| -> 6 # 22| 6 -#-----| -> ... *= ... +#-----| -> ... * ... exit.rb: # 1| enter m1 @@ -2934,14 +2988,20 @@ loops.rb: # 3| x #-----| -> call to puts -# 4| ... -= ... +# 4| x #-----| -> x +# 4| ... = ... +#-----| -> x + +# 4| ... - ... +#-----| -> ... = ... + # 4| x #-----| -> 1 # 4| 1 -#-----| -> ... -= ... +#-----| -> ... - ... # 8| enter m2 #-----| -> x @@ -2982,14 +3042,20 @@ loops.rb: # 10| x #-----| -> call to puts -# 11| ... -= ... +# 11| x #-----| -> x +# 11| ... = ... +#-----| -> x + +# 11| ... - ... +#-----| -> ... = ... + # 11| x #-----| -> 1 # 11| 1 -#-----| -> ... -= ... +#-----| -> ... - ... # 12| if ... #-----| -> self diff --git a/ql/test/library-tests/controlflow/graph/Cfg.ql b/ql/test/library-tests/controlflow/graph/Cfg.ql new file mode 100644 index 00000000000..2217d9dba83 --- /dev/null +++ b/ql/test/library-tests/controlflow/graph/Cfg.ql @@ -0,0 +1,9 @@ +/** + * @kind graph + */ + +import codeql_ruby.controlflow.internal.Cfg + +class MyRelevantCfgNode extends RelevantCfgNode { + MyRelevantCfgNode() { exists(this) } +} diff --git a/ql/test/library-tests/controlflow/graph/Cfg.qlref b/ql/test/library-tests/controlflow/graph/Cfg.qlref deleted file mode 100644 index fb0ac5085b2..00000000000 --- a/ql/test/library-tests/controlflow/graph/Cfg.qlref +++ /dev/null @@ -1 +0,0 @@ -codeql_ruby/controlflow/internal/Cfg.ql \ No newline at end of file diff --git a/ql/test/library-tests/dataflow/local/DataflowStep.expected b/ql/test/library-tests/dataflow/local/DataflowStep.expected index a41b0df807f..2fc9deb8962 100644 --- a/ql/test/library-tests/dataflow/local/DataflowStep.expected +++ b/ql/test/library-tests/dataflow/local/DataflowStep.expected @@ -14,9 +14,10 @@ | local_dataflow.rb:5:7:5:13 | ( ... ) | local_dataflow.rb:5:3:5:13 | ... = ... | | local_dataflow.rb:5:8:5:12 | ... = ... | local_dataflow.rb:5:7:5:13 | ( ... ) | | local_dataflow.rb:5:12:5:12 | a | local_dataflow.rb:5:8:5:12 | ... = ... | -| local_dataflow.rb:5:12:5:12 | a | local_dataflow.rb:6:8:6:8 | a | +| local_dataflow.rb:5:12:5:12 | a | local_dataflow.rb:6:8:6:13 | a | | local_dataflow.rb:6:7:6:14 | ( ... ) | local_dataflow.rb:6:3:6:14 | ... = ... | -| local_dataflow.rb:6:8:6:13 | ... += ... | local_dataflow.rb:6:7:6:14 | ( ... ) | +| local_dataflow.rb:6:8:6:13 | ... + ... | local_dataflow.rb:6:8:6:13 | ... = ... | +| local_dataflow.rb:6:8:6:13 | ... = ... | local_dataflow.rb:6:7:6:14 | ( ... ) | | local_dataflow.rb:9:1:9:15 | ... = ... | local_dataflow.rb:10:14:10:18 | array | | local_dataflow.rb:9:9:9:15 | [...] | local_dataflow.rb:9:1:9:15 | ... = ... | | local_dataflow.rb:9:9:9:15 | [...] | local_dataflow.rb:9:1:9:15 | ... = ... | diff --git a/ql/test/library-tests/variables/ssa.expected b/ql/test/library-tests/variables/ssa.expected index f6aad2b343d..032dd9d9699 100644 --- a/ql/test/library-tests/variables/ssa.expected +++ b/ql/test/library-tests/variables/ssa.expected @@ -42,7 +42,7 @@ definition | scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | | scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | | scopes.rb:9:9:18:3 | | scopes.rb:7:1:7:1 | a | -| scopes.rb:11:4:11:9 | ... += ... | scopes.rb:7:1:7:1 | a | +| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:7:1:7:1 | a | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:7:13:7 | b | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:11:13:11 | c | @@ -55,7 +55,7 @@ definition | ssa.rb:10:5:10:9 | ... = ... | ssa.rb:2:3:2:3 | i | | ssa.rb:18:8:18:8 | x | ssa.rb:18:8:18:8 | x | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | -| ssa.rb:21:5:21:10 | ... -= ... | ssa.rb:18:8:18:8 | x | +| ssa.rb:21:5:21:10 | ... = ... | ssa.rb:18:8:18:8 | x | | ssa.rb:25:1:30:3 | | ssa.rb:26:7:26:10 | elem | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | | ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | @@ -72,13 +72,13 @@ definition | ssa.rb:53:8:53:10 | foo | ssa.rb:53:8:53:10 | foo | | ssa.rb:54:3:54:11 | ... = ... | ssa.rb:54:3:54:3 | x | | ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | -| ssa.rb:60:3:60:9 | ... += ... | ssa.rb:59:3:59:3 | x | +| ssa.rb:60:3:60:9 | ... = ... | ssa.rb:59:3:59:3 | x | | ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | | ssa.rb:65:3:65:15 | ... = ... | ssa.rb:65:3:65:10 | captured | | ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | | ssa.rb:66:11:70:5 | | ssa.rb:65:3:65:10 | captured | | ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | -| ssa.rb:69:5:69:17 | ... += ... | ssa.rb:65:3:65:10 | captured | +| ssa.rb:69:5:69:17 | ... = ... | ssa.rb:65:3:65:10 | captured | | ssa.rb:75:3:75:14 | ... = ... | ssa.rb:75:3:75:10 | captured | | ssa.rb:76:7:78:5 | | ssa.rb:75:3:75:10 | captured | | ssa.rb:82:3:82:14 | ... = ... | ssa.rb:82:3:82:10 | captured | @@ -124,8 +124,8 @@ read | scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a | | scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a | | scopes.rb:9:9:18:3 | | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | -| scopes.rb:9:9:18:3 | | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a | -| scopes.rb:11:4:11:9 | ... += ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a | +| scopes.rb:9:9:18:3 | | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:9 | a | +| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:11:13:11 | c | scopes.rb:16:9:16:9 | c | @@ -145,7 +145,7 @@ read | ssa.rb:10:5:10:9 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:12:10:12:10 | i | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:19:9:19:9 | x | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:20:10:20:10 | x | -| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:5 | x | +| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:10 | x | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements | | ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem | | ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | @@ -156,12 +156,12 @@ read | ssa.rb:50:3:50:8 | phi | ssa.rb:49:14:49:14 | y | ssa.rb:50:8:50:8 | y | | ssa.rb:53:8:53:10 | foo | ssa.rb:53:8:53:10 | foo | ssa.rb:54:7:54:9 | foo | | ssa.rb:54:3:54:11 | ... = ... | ssa.rb:54:3:54:3 | x | ssa.rb:55:8:55:8 | x | -| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:3 | x | -| ssa.rb:60:3:60:9 | ... += ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x | +| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:9 | x | +| ssa.rb:60:3:60:9 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x | | ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a | | ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured | | ssa.rb:66:11:70:5 | | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | -| ssa.rb:66:11:70:5 | | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured | +| ssa.rb:66:11:70:5 | | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:17 | captured | | ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a | | ssa.rb:76:7:78:5 | | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured | | ssa.rb:84:10:86:8 | | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | @@ -204,7 +204,7 @@ firstRead | scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a | | scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a | | scopes.rb:9:9:18:3 | | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | -| scopes.rb:11:4:11:9 | ... += ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a | +| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:11:13:11 | c | scopes.rb:16:9:16:9 | c | @@ -226,8 +226,8 @@ firstRead | ssa.rb:50:3:50:8 | phi | ssa.rb:49:14:49:14 | y | ssa.rb:50:8:50:8 | y | | ssa.rb:53:8:53:10 | foo | ssa.rb:53:8:53:10 | foo | ssa.rb:54:7:54:9 | foo | | ssa.rb:54:3:54:11 | ... = ... | ssa.rb:54:3:54:3 | x | ssa.rb:55:8:55:8 | x | -| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:3 | x | -| ssa.rb:60:3:60:9 | ... += ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x | +| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:9 | x | +| ssa.rb:60:3:60:9 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x | | ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a | | ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured | | ssa.rb:66:11:70:5 | | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | @@ -272,8 +272,8 @@ lastRead | parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x | | scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a | | scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a | -| scopes.rb:9:9:18:3 | | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a | -| scopes.rb:11:4:11:9 | ... += ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a | +| scopes.rb:9:9:18:3 | | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:9 | a | +| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:11:13:11 | c | scopes.rb:16:9:16:9 | c | @@ -285,7 +285,7 @@ lastRead | ssa.rb:6:5:6:9 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:8:10:8:10 | i | | ssa.rb:10:5:10:9 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:12:10:12:10 | i | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:19:9:19:9 | x | -| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:5 | x | +| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:10 | x | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements | | ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem | | ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | @@ -296,11 +296,11 @@ lastRead | ssa.rb:50:3:50:8 | phi | ssa.rb:49:14:49:14 | y | ssa.rb:50:8:50:8 | y | | ssa.rb:53:8:53:10 | foo | ssa.rb:53:8:53:10 | foo | ssa.rb:54:7:54:9 | foo | | ssa.rb:54:3:54:11 | ... = ... | ssa.rb:54:3:54:3 | x | ssa.rb:55:8:55:8 | x | -| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:3 | x | -| ssa.rb:60:3:60:9 | ... += ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x | +| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:9 | x | +| ssa.rb:60:3:60:9 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x | | ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a | | ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured | -| ssa.rb:66:11:70:5 | | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured | +| ssa.rb:66:11:70:5 | | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:17 | captured | | ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a | | ssa.rb:76:7:78:5 | | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured | | ssa.rb:84:10:86:8 | | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | @@ -308,7 +308,7 @@ adjacentReads | nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:14:16:14:16 | a | nested_scopes.rb:15:11:15:11 | a | | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | parameters.rb:11:14:11:19 | pizzas | | parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name | parameters.rb:26:8:26:11 | name | -| scopes.rb:9:9:18:3 | | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a | +| scopes.rb:9:9:18:3 | | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:9 | a | | scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:28:8:28:8 | x | scopes.rb:31:10:31:10 | x | | scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:31:10:31:10 | x | scopes.rb:34:7:34:7 | x | | scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:34:7:34:7 | x | scopes.rb:34:14:34:14 | x | @@ -317,8 +317,8 @@ adjacentReads | ssa.rb:6:5:6:9 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:7:10:7:10 | i | ssa.rb:8:10:8:10 | i | | ssa.rb:10:5:10:9 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:11:10:11:10 | i | ssa.rb:12:10:12:10 | i | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:19:9:19:9 | x | ssa.rb:20:10:20:10 | x | -| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:20:10:20:10 | x | ssa.rb:21:5:21:5 | x | -| ssa.rb:66:11:70:5 | | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | ssa.rb:69:5:69:12 | captured | +| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:20:10:20:10 | x | ssa.rb:21:5:21:10 | x | +| ssa.rb:66:11:70:5 | | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | ssa.rb:69:5:69:17 | captured | phi | parameters.rb:37:3:37:18 | phi | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | | | parameters.rb:37:3:37:18 | phi | parameters.rb:35:16:35:16 | b | parameters.rb:35:16:35:20 | ... = ... | @@ -329,7 +329,7 @@ phi | ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:6:5:6:9 | ... = ... | | ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:10:5:10:9 | ... = ... | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:18:8:18:8 | x | -| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:10 | ... -= ... | +| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:10 | ... = ... | | ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:25:1:30:3 | | | ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | | ssa.rb:45:3:45:12 | phi | ssa.rb:45:3:45:3 | x | ssa.rb:44:1:47:3 | | diff --git a/ql/test/library-tests/variables/varaccess.expected b/ql/test/library-tests/variables/varaccess.expected index 55ce10e6324..f611922dfbc 100644 --- a/ql/test/library-tests/variables/varaccess.expected +++ b/ql/test/library-tests/variables/varaccess.expected @@ -103,6 +103,7 @@ variableAccess | scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x | scopes.rb:9:9:18:3 | do ... end | | scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb | | scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb | +| scopes.rb:11:4:11:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb | | scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb | | scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb | | scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | do ... end | @@ -139,6 +140,7 @@ variableAccess | ssa.rb:19:9:19:9 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 | | ssa.rb:20:10:20:10 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 | | ssa.rb:21:5:21:5 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 | +| ssa.rb:21:5:21:10 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:25:1:30:3 | m2 | | ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:25:1:30:3 | m2 | | ssa.rb:26:15:26:22 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:25:1:30:3 | m2 | @@ -161,6 +163,7 @@ variableAccess | ssa.rb:55:8:55:8 | x | ssa.rb:54:3:54:3 | x | ssa.rb:53:1:56:3 | m7 | | ssa.rb:59:3:59:3 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | m8 | | ssa.rb:60:3:60:3 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | m8 | +| ssa.rb:60:3:60:9 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | m8 | | ssa.rb:61:8:61:8 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | m8 | | ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:64:1:72:3 | m9 | | ssa.rb:65:3:65:10 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 | @@ -169,6 +172,7 @@ variableAccess | ssa.rb:67:10:67:10 | a | ssa.rb:66:15:66:15 | a | ssa.rb:66:11:70:5 | do ... end | | ssa.rb:68:10:68:17 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 | | ssa.rb:69:5:69:12 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 | +| ssa.rb:69:5:69:17 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 | | ssa.rb:71:8:71:15 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 | | ssa.rb:75:3:75:10 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:74:1:79:3 | m10 | | ssa.rb:77:15:77:22 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:74:1:79:3 | m10 | @@ -205,6 +209,7 @@ explicitWrite | scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:8 | ... = ... | | scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:5 | ... = ... | | scopes.rb:11:4:11:4 | a | scopes.rb:11:4:11:9 | ... += ... | +| scopes.rb:11:4:11:4 | a | scopes.rb:11:4:11:9 | ... = ... | | scopes.rb:13:4:13:4 | a | scopes.rb:13:4:13:32 | ... = ... | | scopes.rb:13:7:13:7 | b | scopes.rb:13:4:13:32 | ... = ... | | scopes.rb:13:11:13:11 | c | scopes.rb:13:4:13:32 | ... = ... | @@ -220,14 +225,17 @@ explicitWrite | ssa.rb:6:5:6:5 | i | ssa.rb:6:5:6:9 | ... = ... | | ssa.rb:10:5:10:5 | i | ssa.rb:10:5:10:9 | ... = ... | | ssa.rb:21:5:21:5 | x | ssa.rb:21:5:21:10 | ... -= ... | +| ssa.rb:21:5:21:5 | x | ssa.rb:21:5:21:10 | ... = ... | | ssa.rb:40:3:40:4 | m3 | ssa.rb:40:3:40:9 | ... = ... | | ssa.rb:45:3:45:3 | x | ssa.rb:45:3:45:7 | ... = ... | | ssa.rb:49:14:49:14 | y | ssa.rb:49:14:49:19 | ... = ... | | ssa.rb:54:3:54:3 | x | ssa.rb:54:3:54:11 | ... = ... | | ssa.rb:59:3:59:3 | x | ssa.rb:59:3:59:8 | ... = ... | | ssa.rb:60:3:60:3 | x | ssa.rb:60:3:60:9 | ... += ... | +| ssa.rb:60:3:60:3 | x | ssa.rb:60:3:60:9 | ... = ... | | ssa.rb:65:3:65:10 | captured | ssa.rb:65:3:65:15 | ... = ... | | ssa.rb:69:5:69:12 | captured | ssa.rb:69:5:69:17 | ... += ... | +| ssa.rb:69:5:69:12 | captured | ssa.rb:69:5:69:17 | ... = ... | | ssa.rb:75:3:75:10 | captured | ssa.rb:75:3:75:14 | ... = ... | | ssa.rb:82:3:82:10 | captured | ssa.rb:82:3:82:14 | ... = ... | implicitWrite @@ -316,7 +324,7 @@ readAccess | scopes.rb:5:9:5:9 | a | | scopes.rb:8:6:8:6 | a | | scopes.rb:10:9:10:9 | a | -| scopes.rb:11:4:11:4 | a | +| scopes.rb:11:4:11:9 | a | | scopes.rb:12:9:12:9 | a | | scopes.rb:14:9:14:9 | a | | scopes.rb:15:9:15:9 | b | @@ -338,7 +346,7 @@ readAccess | ssa.rb:15:8:15:8 | i | | ssa.rb:19:9:19:9 | x | | ssa.rb:20:10:20:10 | x | -| ssa.rb:21:5:21:5 | x | +| ssa.rb:21:5:21:10 | x | | ssa.rb:26:15:26:22 | elements | | ssa.rb:27:10:27:13 | elem | | ssa.rb:29:8:29:11 | elem | @@ -349,12 +357,12 @@ readAccess | ssa.rb:50:8:50:8 | y | | ssa.rb:54:7:54:9 | foo | | ssa.rb:55:8:55:8 | x | -| ssa.rb:60:3:60:3 | x | +| ssa.rb:60:3:60:9 | x | | ssa.rb:61:8:61:8 | x | | ssa.rb:66:3:66:3 | a | | ssa.rb:67:10:67:10 | a | | ssa.rb:68:10:68:17 | captured | -| ssa.rb:69:5:69:12 | captured | +| ssa.rb:69:5:69:17 | captured | | ssa.rb:71:8:71:15 | captured | | ssa.rb:77:15:77:22 | captured | | ssa.rb:85:15:85:22 | captured | From 89be8d87107beb1d1b4e8d24485f30f5e9720a17 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 13 May 2021 12:59:16 +0100 Subject: [PATCH 52/66] Apply suggestions from code review Co-authored-by: Arthur Baars --- ql/src/queries/security/cwe-732/WeakFilePermissions.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql index 79fd3f8b663..d75aa6831e7 100644 --- a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -52,8 +52,8 @@ class PermissivePermissionsExpr extends Expr { (acc = access(world_permission(perm)) or acc = access(group_permission(perm))) ) or - // adding/setting read or write permissions for all/group/owner - this.(StringLiteral).getValueText().regexpMatch(".*[ago][^-=+]*[+=]*[xXst]*[rw].*") + // adding/setting read or write permissions for all/group/other + this.(StringLiteral).getValueText().regexpMatch(".*[ago][^-=+]*[+=][xXst]*[rw].*") } } From 0d1c4a12907effdfb0b59fd96c3780fe0e125380 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 13 May 2021 13:06:45 +0100 Subject: [PATCH 53/66] document that the WeakFilePermissions access predicate should return at most one value --- ql/src/queries/security/cwe-732/WeakFilePermissions.ql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql index d75aa6831e7..7d6916e667c 100644 --- a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -40,6 +40,8 @@ bindingset[p] string access(int p) { p.bitAnd(2) != 0 and result = "writable" or + // report only the "most permissive" permission, i.e. report the file as + // readable only if it is not also writable p.bitAnd(2) = 0 and p.bitAnd(4) != 0 and result = "readable" } From b2f2f786acecd88d68a18a453379b951c7ac2c68 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 13 May 2021 13:22:14 +0100 Subject: [PATCH 54/66] allow the WeakFilePermissions access predicate to return multiple values --- ql/src/queries/security/cwe-732/WeakFilePermissions.ql | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql index 7d6916e667c..41c0edceb16 100644 --- a/ql/src/queries/security/cwe-732/WeakFilePermissions.ql +++ b/ql/src/queries/security/cwe-732/WeakFilePermissions.ql @@ -40,9 +40,7 @@ bindingset[p] string access(int p) { p.bitAnd(2) != 0 and result = "writable" or - // report only the "most permissive" permission, i.e. report the file as - // readable only if it is not also writable - p.bitAnd(2) = 0 and p.bitAnd(4) != 0 and result = "readable" + p.bitAnd(4) != 0 and result = "readable" } /** An expression specifing a file permission that allows group/others read or write access */ From 277a6a020a88a855ffcb90a26067645f99e3b60e Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 13 May 2021 13:37:32 +0100 Subject: [PATCH 55/66] diagnostics: use debug rather than hidden terminology, and leave gaps for other severities --- extractor/src/extractor.rs | 2 +- generator/src/main.rs | 8 ++++---- ql/src/codeql_ruby/Diagnostics.qll | 8 ++++---- ql/src/ruby.dbscheme | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/extractor/src/extractor.rs b/extractor/src/extractor.rs index 33d06358a2a..7c9e64a4f7d 100644 --- a/extractor/src/extractor.rs +++ b/extractor/src/extractor.rs @@ -281,7 +281,7 @@ impl Visitor<'_> { "diagnostics", vec![ Arg::Label(id), - Arg::Int(3), // severity 3 = error + Arg::Int(40), // severity 40 = error Arg::String("parse_error".to_string()), Arg::String(error_message), Arg::String(full_error_message), diff --git a/generator/src/main.rs b/generator/src/main.rs index c3561e8dc68..238e659209b 100644 --- a/generator/src/main.rs +++ b/generator/src/main.rs @@ -645,10 +645,10 @@ fn create_diagnostics<'a>() -> (dbscheme::Case<'a>, dbscheme::Table<'a>) { ], }; let severities: Vec<(usize, &str)> = vec![ - (0, "diagnostic_hidden"), - (1, "diagnostic_info"), - (2, "diagnostic_warning"), - (3, "diagnostic_error"), + (10, "diagnostic_debug"), + (20, "diagnostic_info"), + (30, "diagnostic_warning"), + (40, "diagnostic_error"), ]; let case = dbscheme::Case { name: "diagnostic", diff --git a/ql/src/codeql_ruby/Diagnostics.qll b/ql/src/codeql_ruby/Diagnostics.qll index d97030b57e7..b8995c01bc2 100644 --- a/ql/src/codeql_ruby/Diagnostics.qll +++ b/ql/src/codeql_ruby/Diagnostics.qll @@ -17,13 +17,13 @@ class Diagnostic extends @diagnostic { /** Gets a string representation of the severity of this diagnostic. */ string getSeverityText() { - severity = 0 and result = "Hidden" + severity = 10 and result = "Debug" or - severity = 1 and result = "Info" + severity = 20 and result = "Info" or - severity = 2 and result = "Warning" + severity = 30 and result = "Warning" or - severity = 3 and result = "Error" + severity = 40 and result = "Error" } /** Gets the error code associated with this diagnostic, e.g. parse_error. */ diff --git a/ql/src/ruby.dbscheme b/ql/src/ruby.dbscheme index e9164e21ebf..40be81bc208 100644 --- a/ql/src/ruby.dbscheme +++ b/ql/src/ruby.dbscheme @@ -1247,10 +1247,10 @@ diagnostics( ); case @diagnostic.severity of - 0 = @diagnostic_hidden -| 1 = @diagnostic_info -| 2 = @diagnostic_warning -| 3 = @diagnostic_error + 10 = @diagnostic_debug +| 20 = @diagnostic_info +| 30 = @diagnostic_warning +| 40 = @diagnostic_error ; From dc3c5926f5be9091cc2bbff2d32d4a0006b821c2 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 13 May 2021 13:45:02 +0100 Subject: [PATCH 56/66] add a db upgrade for the diagnostics table --- .../old.dbscheme | 1250 ++++++++++++++++ .../ruby.dbscheme | 1267 +++++++++++++++++ .../upgrade.properties | 2 + 3 files changed, 2519 insertions(+) create mode 100644 upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/old.dbscheme create mode 100644 upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/ruby.dbscheme create mode 100644 upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/upgrade.properties diff --git a/upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/old.dbscheme b/upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/old.dbscheme new file mode 100644 index 00000000000..8725deeb2fa --- /dev/null +++ b/upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/old.dbscheme @@ -0,0 +1,1250 @@ +// 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 +); + +@sourceline = @file + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @file | @folder + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +sourceLocationPrefix( + string prefix: string ref +); + +@underscore_arg = @assignment | @binary | @conditional | @operator_assignment | @range | @unary | @underscore_primary + +@underscore_lhs = @call | @element_reference | @scope_resolution | @token_false | @token_nil | @token_true | @underscore_variable + +@underscore_method_name = @delimited_symbol | @setter | @token_class_variable | @token_constant | @token_global_variable | @token_identifier | @token_instance_variable | @token_operator | @token_simple_symbol + +@underscore_primary = @array | @begin | @break | @case__ | @chained_string | @class | @delimited_symbol | @for | @hash | @if | @lambda | @method | @module | @next | @parenthesized_statements | @rational | @redo | @regex | @retry | @return | @singleton_class | @singleton_method | @string__ | @string_array | @subshell | @symbol_array | @token_character | @token_complex | @token_float | @token_heredoc_beginning | @token_integer | @token_simple_symbol | @unary | @underscore_lhs | @unless | @until | @while | @yield + +@underscore_statement = @alias | @assignment | @begin_block | @binary | @break | @call | @end_block | @if_modifier | @next | @operator_assignment | @rescue_modifier | @return | @unary | @undef | @underscore_arg | @unless_modifier | @until_modifier | @while_modifier | @yield + +@underscore_variable = @token_class_variable | @token_constant | @token_global_variable | @token_identifier | @token_instance_variable | @token_self | @token_super + +alias_def( + unique int id: @alias, + int alias: @underscore_method_name ref, + int name: @underscore_method_name ref, + int loc: @location ref +); + +@argument_list_child_type = @block_argument | @break | @call | @hash_splat_argument | @next | @pair | @return | @splat_argument | @underscore_arg | @yield + +#keyset[argument_list, index] +argument_list_child( + int argument_list: @argument_list ref, + int index: int ref, + unique int child: @argument_list_child_type ref +); + +argument_list_def( + unique int id: @argument_list, + int loc: @location ref +); + +@array_child_type = @block_argument | @break | @call | @hash_splat_argument | @next | @pair | @return | @splat_argument | @underscore_arg | @yield + +#keyset[array, index] +array_child( + int array: @array ref, + int index: int ref, + unique int child: @array_child_type ref +); + +array_def( + unique int id: @array, + int loc: @location ref +); + +@assignment_left_type = @left_assignment_list | @underscore_lhs + +@assignment_right_type = @break | @call | @next | @return | @right_assignment_list | @splat_argument | @underscore_arg | @yield + +assignment_def( + unique int id: @assignment, + int left: @assignment_left_type ref, + int right: @assignment_right_type ref, + int loc: @location ref +); + +@bare_string_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[bare_string, index] +bare_string_child( + int bare_string: @bare_string ref, + int index: int ref, + unique int child: @bare_string_child_type ref +); + +bare_string_def( + unique int id: @bare_string, + int loc: @location ref +); + +@bare_symbol_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[bare_symbol, index] +bare_symbol_child( + int bare_symbol: @bare_symbol ref, + int index: int ref, + unique int child: @bare_symbol_child_type ref +); + +bare_symbol_def( + unique int id: @bare_symbol, + int loc: @location ref +); + +@begin_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[begin, index] +begin_child( + int begin: @begin ref, + int index: int ref, + unique int child: @begin_child_type ref +); + +begin_def( + unique int id: @begin, + int loc: @location ref +); + +@begin_block_child_type = @token_empty_statement | @underscore_statement + +#keyset[begin_block, index] +begin_block_child( + int begin_block: @begin_block ref, + int index: int ref, + unique int child: @begin_block_child_type ref +); + +begin_block_def( + unique int id: @begin_block, + int loc: @location ref +); + +@binary_left_type = @break | @call | @next | @return | @underscore_arg | @yield + +case @binary.operator of + 0 = @binary_bangequal +| 1 = @binary_bangtilde +| 2 = @binary_percent +| 3 = @binary_ampersand +| 4 = @binary_ampersandampersand +| 5 = @binary_star +| 6 = @binary_starstar +| 7 = @binary_plus +| 8 = @binary_minus +| 9 = @binary_slash +| 10 = @binary_langle +| 11 = @binary_langlelangle +| 12 = @binary_langleequal +| 13 = @binary_langleequalrangle +| 14 = @binary_equalequal +| 15 = @binary_equalequalequal +| 16 = @binary_equaltilde +| 17 = @binary_rangle +| 18 = @binary_rangleequal +| 19 = @binary_ranglerangle +| 20 = @binary_caret +| 21 = @binary_and +| 22 = @binary_or +| 23 = @binary_pipe +| 24 = @binary_pipepipe +; + + +@binary_right_type = @break | @call | @next | @return | @underscore_arg | @yield + +binary_def( + unique int id: @binary, + int left: @binary_left_type ref, + int operator: int ref, + int right: @binary_right_type ref, + int loc: @location ref +); + +block_parameters( + unique int block: @block ref, + unique int parameters: @block_parameters ref +); + +@block_child_type = @token_empty_statement | @underscore_statement + +#keyset[block, index] +block_child( + int block: @block ref, + int index: int ref, + unique int child: @block_child_type ref +); + +block_def( + unique int id: @block, + int loc: @location ref +); + +block_argument_def( + unique int id: @block_argument, + int child: @underscore_arg ref, + int loc: @location ref +); + +block_parameter_def( + unique int id: @block_parameter, + int name: @token_identifier ref, + int loc: @location ref +); + +@block_parameters_child_type = @block_parameter | @destructured_parameter | @hash_splat_parameter | @keyword_parameter | @optional_parameter | @splat_parameter | @token_identifier + +#keyset[block_parameters, index] +block_parameters_child( + int block_parameters: @block_parameters ref, + int index: int ref, + unique int child: @block_parameters_child_type ref +); + +block_parameters_def( + unique int id: @block_parameters, + int loc: @location ref +); + +break_child( + unique int break: @break ref, + unique int child: @argument_list ref +); + +break_def( + unique int id: @break, + int loc: @location ref +); + +call_arguments( + unique int call: @call ref, + unique int arguments: @argument_list ref +); + +@call_block_type = @block | @do_block + +call_block( + unique int call: @call ref, + unique int block: @call_block_type ref +); + +@call_method_type = @argument_list | @scope_resolution | @token_operator | @underscore_variable + +@call_receiver_type = @call | @underscore_primary + +call_receiver( + unique int call: @call ref, + unique int receiver: @call_receiver_type ref +); + +call_def( + unique int id: @call, + int method: @call_method_type ref, + int loc: @location ref +); + +case_value( + unique int case__: @case__ ref, + unique int value: @underscore_statement ref +); + +@case_child_type = @else | @when + +#keyset[case__, index] +case_child( + int case__: @case__ ref, + int index: int ref, + unique int child: @case_child_type ref +); + +case_def( + unique int id: @case__, + int loc: @location ref +); + +#keyset[chained_string, index] +chained_string_child( + int chained_string: @chained_string ref, + int index: int ref, + unique int child: @string__ ref +); + +chained_string_def( + unique int id: @chained_string, + int loc: @location ref +); + +@class_name_type = @scope_resolution | @token_constant + +class_superclass( + unique int class: @class ref, + unique int superclass: @superclass ref +); + +@class_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[class, index] +class_child( + int class: @class ref, + int index: int ref, + unique int child: @class_child_type ref +); + +class_def( + unique int id: @class, + int name: @class_name_type ref, + int loc: @location ref +); + +conditional_def( + unique int id: @conditional, + int alternative: @underscore_arg ref, + int condition: @underscore_arg ref, + int consequence: @underscore_arg ref, + int loc: @location ref +); + +@delimited_symbol_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[delimited_symbol, index] +delimited_symbol_child( + int delimited_symbol: @delimited_symbol ref, + int index: int ref, + unique int child: @delimited_symbol_child_type ref +); + +delimited_symbol_def( + unique int id: @delimited_symbol, + int loc: @location ref +); + +@destructured_left_assignment_child_type = @destructured_left_assignment | @rest_assignment | @underscore_lhs + +#keyset[destructured_left_assignment, index] +destructured_left_assignment_child( + int destructured_left_assignment: @destructured_left_assignment ref, + int index: int ref, + unique int child: @destructured_left_assignment_child_type ref +); + +destructured_left_assignment_def( + unique int id: @destructured_left_assignment, + int loc: @location ref +); + +@destructured_parameter_child_type = @block_parameter | @destructured_parameter | @hash_splat_parameter | @keyword_parameter | @optional_parameter | @splat_parameter | @token_identifier + +#keyset[destructured_parameter, index] +destructured_parameter_child( + int destructured_parameter: @destructured_parameter ref, + int index: int ref, + unique int child: @destructured_parameter_child_type ref +); + +destructured_parameter_def( + unique int id: @destructured_parameter, + int loc: @location ref +); + +@do_child_type = @token_empty_statement | @underscore_statement + +#keyset[do, index] +do_child( + int do: @do ref, + int index: int ref, + unique int child: @do_child_type ref +); + +do_def( + unique int id: @do, + int loc: @location ref +); + +do_block_parameters( + unique int do_block: @do_block ref, + unique int parameters: @block_parameters ref +); + +@do_block_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[do_block, index] +do_block_child( + int do_block: @do_block ref, + int index: int ref, + unique int child: @do_block_child_type ref +); + +do_block_def( + unique int id: @do_block, + int loc: @location ref +); + +@element_reference_child_type = @block_argument | @break | @call | @hash_splat_argument | @next | @pair | @return | @splat_argument | @underscore_arg | @yield + +#keyset[element_reference, index] +element_reference_child( + int element_reference: @element_reference ref, + int index: int ref, + unique int child: @element_reference_child_type ref +); + +element_reference_def( + unique int id: @element_reference, + int object: @underscore_primary ref, + int loc: @location ref +); + +@else_child_type = @token_empty_statement | @underscore_statement + +#keyset[else, index] +else_child( + int else: @else ref, + int index: int ref, + unique int child: @else_child_type ref +); + +else_def( + unique int id: @else, + int loc: @location ref +); + +@elsif_alternative_type = @else | @elsif + +elsif_alternative( + unique int elsif: @elsif ref, + unique int alternative: @elsif_alternative_type ref +); + +elsif_consequence( + unique int elsif: @elsif ref, + unique int consequence: @then ref +); + +elsif_def( + unique int id: @elsif, + int condition: @underscore_statement ref, + int loc: @location ref +); + +@end_block_child_type = @token_empty_statement | @underscore_statement + +#keyset[end_block, index] +end_block_child( + int end_block: @end_block ref, + int index: int ref, + unique int child: @end_block_child_type ref +); + +end_block_def( + unique int id: @end_block, + int loc: @location ref +); + +@ensure_child_type = @token_empty_statement | @underscore_statement + +#keyset[ensure, index] +ensure_child( + int ensure: @ensure ref, + int index: int ref, + unique int child: @ensure_child_type ref +); + +ensure_def( + unique int id: @ensure, + int loc: @location ref +); + +exception_variable_def( + unique int id: @exception_variable, + int child: @underscore_lhs ref, + int loc: @location ref +); + +@exceptions_child_type = @splat_argument | @underscore_arg + +#keyset[exceptions, index] +exceptions_child( + int exceptions: @exceptions ref, + int index: int ref, + unique int child: @exceptions_child_type ref +); + +exceptions_def( + unique int id: @exceptions, + int loc: @location ref +); + +@for_pattern_type = @left_assignment_list | @underscore_lhs + +for_def( + unique int id: @for, + int body: @do ref, + int pattern: @for_pattern_type ref, + int value: @in ref, + int loc: @location ref +); + +@hash_child_type = @hash_splat_argument | @pair + +#keyset[hash, index] +hash_child( + int hash: @hash ref, + int index: int ref, + unique int child: @hash_child_type ref +); + +hash_def( + unique int id: @hash, + int loc: @location ref +); + +hash_splat_argument_def( + unique int id: @hash_splat_argument, + int child: @underscore_arg ref, + int loc: @location ref +); + +hash_splat_parameter_name( + unique int hash_splat_parameter: @hash_splat_parameter ref, + unique int name: @token_identifier ref +); + +hash_splat_parameter_def( + unique int id: @hash_splat_parameter, + int loc: @location ref +); + +@heredoc_body_child_type = @interpolation | @token_escape_sequence | @token_heredoc_content | @token_heredoc_end + +#keyset[heredoc_body, index] +heredoc_body_child( + int heredoc_body: @heredoc_body ref, + int index: int ref, + unique int child: @heredoc_body_child_type ref +); + +heredoc_body_def( + unique int id: @heredoc_body, + int loc: @location ref +); + +@if_alternative_type = @else | @elsif + +if_alternative( + unique int if: @if ref, + unique int alternative: @if_alternative_type ref +); + +if_consequence( + unique int if: @if ref, + unique int consequence: @then ref +); + +if_def( + unique int id: @if, + int condition: @underscore_statement ref, + int loc: @location ref +); + +@if_modifier_condition_type = @break | @call | @next | @return | @underscore_arg | @yield + +if_modifier_def( + unique int id: @if_modifier, + int body: @underscore_statement ref, + int condition: @if_modifier_condition_type ref, + int loc: @location ref +); + +in_def( + unique int id: @in, + int child: @underscore_arg ref, + int loc: @location ref +); + +@interpolation_child_type = @token_empty_statement | @underscore_statement + +#keyset[interpolation, index] +interpolation_child( + int interpolation: @interpolation ref, + int index: int ref, + unique int child: @interpolation_child_type ref +); + +interpolation_def( + unique int id: @interpolation, + int loc: @location ref +); + +keyword_parameter_value( + unique int keyword_parameter: @keyword_parameter ref, + unique int value: @underscore_arg ref +); + +keyword_parameter_def( + unique int id: @keyword_parameter, + int name: @token_identifier ref, + int loc: @location ref +); + +@lambda_body_type = @block | @do_block + +lambda_parameters( + unique int lambda: @lambda ref, + unique int parameters: @lambda_parameters ref +); + +lambda_def( + unique int id: @lambda, + int body: @lambda_body_type ref, + int loc: @location ref +); + +@lambda_parameters_child_type = @block_parameter | @destructured_parameter | @hash_splat_parameter | @keyword_parameter | @optional_parameter | @splat_parameter | @token_identifier + +#keyset[lambda_parameters, index] +lambda_parameters_child( + int lambda_parameters: @lambda_parameters ref, + int index: int ref, + unique int child: @lambda_parameters_child_type ref +); + +lambda_parameters_def( + unique int id: @lambda_parameters, + int loc: @location ref +); + +@left_assignment_list_child_type = @destructured_left_assignment | @rest_assignment | @underscore_lhs + +#keyset[left_assignment_list, index] +left_assignment_list_child( + int left_assignment_list: @left_assignment_list ref, + int index: int ref, + unique int child: @left_assignment_list_child_type ref +); + +left_assignment_list_def( + unique int id: @left_assignment_list, + int loc: @location ref +); + +method_parameters( + unique int method: @method ref, + unique int parameters: @method_parameters ref +); + +@method_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[method, index] +method_child( + int method: @method ref, + int index: int ref, + unique int child: @method_child_type ref +); + +method_def( + unique int id: @method, + int name: @underscore_method_name ref, + int loc: @location ref +); + +@method_parameters_child_type = @block_parameter | @destructured_parameter | @hash_splat_parameter | @keyword_parameter | @optional_parameter | @splat_parameter | @token_identifier + +#keyset[method_parameters, index] +method_parameters_child( + int method_parameters: @method_parameters ref, + int index: int ref, + unique int child: @method_parameters_child_type ref +); + +method_parameters_def( + unique int id: @method_parameters, + int loc: @location ref +); + +@module_name_type = @scope_resolution | @token_constant + +@module_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[module, index] +module_child( + int module: @module ref, + int index: int ref, + unique int child: @module_child_type ref +); + +module_def( + unique int id: @module, + int name: @module_name_type ref, + int loc: @location ref +); + +next_child( + unique int next: @next ref, + unique int child: @argument_list ref +); + +next_def( + unique int id: @next, + int loc: @location ref +); + +case @operator_assignment.operator of + 0 = @operator_assignment_percentequal +| 1 = @operator_assignment_ampersandampersandequal +| 2 = @operator_assignment_ampersandequal +| 3 = @operator_assignment_starstarequal +| 4 = @operator_assignment_starequal +| 5 = @operator_assignment_plusequal +| 6 = @operator_assignment_minusequal +| 7 = @operator_assignment_slashequal +| 8 = @operator_assignment_langlelangleequal +| 9 = @operator_assignment_ranglerangleequal +| 10 = @operator_assignment_caretequal +| 11 = @operator_assignment_pipeequal +| 12 = @operator_assignment_pipepipeequal +; + + +@operator_assignment_right_type = @break | @call | @next | @return | @underscore_arg | @yield + +operator_assignment_def( + unique int id: @operator_assignment, + int left: @underscore_lhs ref, + int operator: int ref, + int right: @operator_assignment_right_type ref, + int loc: @location ref +); + +optional_parameter_def( + unique int id: @optional_parameter, + int name: @token_identifier ref, + int value: @underscore_arg ref, + int loc: @location ref +); + +@pair_key_type = @string__ | @token_hash_key_symbol | @underscore_arg + +pair_def( + unique int id: @pair, + int key__: @pair_key_type ref, + int value: @underscore_arg ref, + int loc: @location ref +); + +@parenthesized_statements_child_type = @token_empty_statement | @underscore_statement + +#keyset[parenthesized_statements, index] +parenthesized_statements_child( + int parenthesized_statements: @parenthesized_statements ref, + int index: int ref, + unique int child: @parenthesized_statements_child_type ref +); + +parenthesized_statements_def( + unique int id: @parenthesized_statements, + int loc: @location ref +); + +@pattern_child_type = @splat_argument | @underscore_arg + +pattern_def( + unique int id: @pattern, + int child: @pattern_child_type ref, + int loc: @location ref +); + +@program_child_type = @token_empty_statement | @token_uninterpreted | @underscore_statement + +#keyset[program, index] +program_child( + int program: @program ref, + int index: int ref, + unique int child: @program_child_type ref +); + +program_def( + unique int id: @program, + int loc: @location ref +); + +range_begin( + unique int range: @range ref, + unique int begin: @underscore_arg ref +); + +range_end( + unique int range: @range ref, + unique int end: @underscore_arg ref +); + +case @range.operator of + 0 = @range_dotdot +| 1 = @range_dotdotdot +; + + +range_def( + unique int id: @range, + int operator: int ref, + int loc: @location ref +); + +@rational_child_type = @token_float | @token_integer + +rational_def( + unique int id: @rational, + int child: @rational_child_type ref, + int loc: @location ref +); + +redo_child( + unique int redo: @redo ref, + unique int child: @argument_list ref +); + +redo_def( + unique int id: @redo, + int loc: @location ref +); + +@regex_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[regex, index] +regex_child( + int regex: @regex ref, + int index: int ref, + unique int child: @regex_child_type ref +); + +regex_def( + unique int id: @regex, + int loc: @location ref +); + +rescue_body( + unique int rescue: @rescue ref, + unique int body: @then ref +); + +rescue_exceptions( + unique int rescue: @rescue ref, + unique int exceptions: @exceptions ref +); + +rescue_variable( + unique int rescue: @rescue ref, + unique int variable: @exception_variable ref +); + +rescue_def( + unique int id: @rescue, + int loc: @location ref +); + +@rescue_modifier_handler_type = @break | @call | @next | @return | @underscore_arg | @yield + +rescue_modifier_def( + unique int id: @rescue_modifier, + int body: @underscore_statement ref, + int handler: @rescue_modifier_handler_type ref, + int loc: @location ref +); + +rest_assignment_child( + unique int rest_assignment: @rest_assignment ref, + unique int child: @underscore_lhs ref +); + +rest_assignment_def( + unique int id: @rest_assignment, + int loc: @location ref +); + +retry_child( + unique int retry: @retry ref, + unique int child: @argument_list ref +); + +retry_def( + unique int id: @retry, + int loc: @location ref +); + +return_child( + unique int return: @return ref, + unique int child: @argument_list ref +); + +return_def( + unique int id: @return, + int loc: @location ref +); + +@right_assignment_list_child_type = @splat_argument | @underscore_arg + +#keyset[right_assignment_list, index] +right_assignment_list_child( + int right_assignment_list: @right_assignment_list ref, + int index: int ref, + unique int child: @right_assignment_list_child_type ref +); + +right_assignment_list_def( + unique int id: @right_assignment_list, + int loc: @location ref +); + +@scope_resolution_name_type = @token_constant | @token_identifier + +scope_resolution_scope( + unique int scope_resolution: @scope_resolution ref, + unique int scope: @underscore_primary ref +); + +scope_resolution_def( + unique int id: @scope_resolution, + int name: @scope_resolution_name_type ref, + int loc: @location ref +); + +setter_def( + unique int id: @setter, + int name: @token_identifier ref, + int loc: @location ref +); + +@singleton_class_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[singleton_class, index] +singleton_class_child( + int singleton_class: @singleton_class ref, + int index: int ref, + unique int child: @singleton_class_child_type ref +); + +singleton_class_def( + unique int id: @singleton_class, + int value: @underscore_arg ref, + int loc: @location ref +); + +@singleton_method_object_type = @underscore_arg | @underscore_variable + +singleton_method_parameters( + unique int singleton_method: @singleton_method ref, + unique int parameters: @method_parameters ref +); + +@singleton_method_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[singleton_method, index] +singleton_method_child( + int singleton_method: @singleton_method ref, + int index: int ref, + unique int child: @singleton_method_child_type ref +); + +singleton_method_def( + unique int id: @singleton_method, + int name: @underscore_method_name ref, + int object: @singleton_method_object_type ref, + int loc: @location ref +); + +splat_argument_def( + unique int id: @splat_argument, + int child: @underscore_arg ref, + int loc: @location ref +); + +splat_parameter_name( + unique int splat_parameter: @splat_parameter ref, + unique int name: @token_identifier ref +); + +splat_parameter_def( + unique int id: @splat_parameter, + int loc: @location ref +); + +@string_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[string__, index] +string_child( + int string__: @string__ ref, + int index: int ref, + unique int child: @string_child_type ref +); + +string_def( + unique int id: @string__, + int loc: @location ref +); + +#keyset[string_array, index] +string_array_child( + int string_array: @string_array ref, + int index: int ref, + unique int child: @bare_string ref +); + +string_array_def( + unique int id: @string_array, + int loc: @location ref +); + +@subshell_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[subshell, index] +subshell_child( + int subshell: @subshell ref, + int index: int ref, + unique int child: @subshell_child_type ref +); + +subshell_def( + unique int id: @subshell, + int loc: @location ref +); + +@superclass_child_type = @break | @call | @next | @return | @underscore_arg | @yield + +superclass_def( + unique int id: @superclass, + int child: @superclass_child_type ref, + int loc: @location ref +); + +#keyset[symbol_array, index] +symbol_array_child( + int symbol_array: @symbol_array ref, + int index: int ref, + unique int child: @bare_symbol ref +); + +symbol_array_def( + unique int id: @symbol_array, + int loc: @location ref +); + +@then_child_type = @token_empty_statement | @underscore_statement + +#keyset[then, index] +then_child( + int then: @then ref, + int index: int ref, + unique int child: @then_child_type ref +); + +then_def( + unique int id: @then, + int loc: @location ref +); + +@unary_operand_type = @break | @call | @next | @parenthesized_statements | @return | @token_float | @token_integer | @underscore_arg | @yield + +case @unary.operator of + 0 = @unary_bang +| 1 = @unary_plus +| 2 = @unary_minus +| 3 = @unary_definedquestion +| 4 = @unary_not +| 5 = @unary_tilde +; + + +unary_def( + unique int id: @unary, + int operand: @unary_operand_type ref, + int operator: int ref, + int loc: @location ref +); + +#keyset[undef, index] +undef_child( + int undef: @undef ref, + int index: int ref, + unique int child: @underscore_method_name ref +); + +undef_def( + unique int id: @undef, + int loc: @location ref +); + +@unless_alternative_type = @else | @elsif + +unless_alternative( + unique int unless: @unless ref, + unique int alternative: @unless_alternative_type ref +); + +unless_consequence( + unique int unless: @unless ref, + unique int consequence: @then ref +); + +unless_def( + unique int id: @unless, + int condition: @underscore_statement ref, + int loc: @location ref +); + +@unless_modifier_condition_type = @break | @call | @next | @return | @underscore_arg | @yield + +unless_modifier_def( + unique int id: @unless_modifier, + int body: @underscore_statement ref, + int condition: @unless_modifier_condition_type ref, + int loc: @location ref +); + +until_def( + unique int id: @until, + int body: @do ref, + int condition: @underscore_statement ref, + int loc: @location ref +); + +@until_modifier_condition_type = @break | @call | @next | @return | @underscore_arg | @yield + +until_modifier_def( + unique int id: @until_modifier, + int body: @underscore_statement ref, + int condition: @until_modifier_condition_type ref, + int loc: @location ref +); + +when_body( + unique int when: @when ref, + unique int body: @then ref +); + +#keyset[when, index] +when_pattern( + int when: @when ref, + int index: int ref, + unique int pattern: @pattern ref +); + +when_def( + unique int id: @when, + int loc: @location ref +); + +while_def( + unique int id: @while, + int body: @do ref, + int condition: @underscore_statement ref, + int loc: @location ref +); + +@while_modifier_condition_type = @break | @call | @next | @return | @underscore_arg | @yield + +while_modifier_def( + unique int id: @while_modifier, + int body: @underscore_statement ref, + int condition: @while_modifier_condition_type ref, + int loc: @location ref +); + +yield_child( + unique int yield: @yield ref, + unique int child: @argument_list ref +); + +yield_def( + unique int id: @yield, + int loc: @location ref +); + +tokeninfo( + unique int id: @token, + int kind: int ref, + int file: @file ref, + int idx: int ref, + string value: string ref, + int loc: @location ref +); + +case @token.kind of + 0 = @reserved_word +| 1 = @token_character +| 2 = @token_class_variable +| 3 = @token_comment +| 4 = @token_complex +| 5 = @token_constant +| 6 = @token_empty_statement +| 7 = @token_escape_sequence +| 8 = @token_false +| 9 = @token_float +| 10 = @token_global_variable +| 11 = @token_hash_key_symbol +| 12 = @token_heredoc_beginning +| 13 = @token_heredoc_content +| 14 = @token_heredoc_end +| 15 = @token_identifier +| 16 = @token_instance_variable +| 17 = @token_integer +| 18 = @token_nil +| 19 = @token_operator +| 20 = @token_self +| 21 = @token_simple_symbol +| 22 = @token_string_content +| 23 = @token_super +| 24 = @token_true +| 25 = @token_uninterpreted +; + + +@ast_node = @alias | @argument_list | @array | @assignment | @bare_string | @bare_symbol | @begin | @begin_block | @binary | @block | @block_argument | @block_parameter | @block_parameters | @break | @call | @case__ | @chained_string | @class | @conditional | @delimited_symbol | @destructured_left_assignment | @destructured_parameter | @do | @do_block | @element_reference | @else | @elsif | @end_block | @ensure | @exception_variable | @exceptions | @for | @hash | @hash_splat_argument | @hash_splat_parameter | @heredoc_body | @if | @if_modifier | @in | @interpolation | @keyword_parameter | @lambda | @lambda_parameters | @left_assignment_list | @method | @method_parameters | @module | @next | @operator_assignment | @optional_parameter | @pair | @parenthesized_statements | @pattern | @program | @range | @rational | @redo | @regex | @rescue | @rescue_modifier | @rest_assignment | @retry | @return | @right_assignment_list | @scope_resolution | @setter | @singleton_class | @singleton_method | @splat_argument | @splat_parameter | @string__ | @string_array | @subshell | @superclass | @symbol_array | @then | @token | @unary | @undef | @unless | @unless_modifier | @until | @until_modifier | @when | @while | @while_modifier | @yield + +@ast_node_parent = @ast_node | @file + +#keyset[parent, parent_index] +ast_node_parent( + int child: @ast_node ref, + int parent: @ast_node_parent ref, + int parent_index: int ref +); + diff --git a/upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/ruby.dbscheme b/upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/ruby.dbscheme new file mode 100644 index 00000000000..40be81bc208 --- /dev/null +++ b/upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/ruby.dbscheme @@ -0,0 +1,1267 @@ +// 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 +); + +@sourceline = @file + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @file | @folder + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +sourceLocationPrefix( + string prefix: string ref +); + +@underscore_arg = @assignment | @binary | @conditional | @operator_assignment | @range | @unary | @underscore_primary + +@underscore_lhs = @call | @element_reference | @scope_resolution | @token_false | @token_nil | @token_true | @underscore_variable + +@underscore_method_name = @delimited_symbol | @setter | @token_class_variable | @token_constant | @token_global_variable | @token_identifier | @token_instance_variable | @token_operator | @token_simple_symbol + +@underscore_primary = @array | @begin | @break | @case__ | @chained_string | @class | @delimited_symbol | @for | @hash | @if | @lambda | @method | @module | @next | @parenthesized_statements | @rational | @redo | @regex | @retry | @return | @singleton_class | @singleton_method | @string__ | @string_array | @subshell | @symbol_array | @token_character | @token_complex | @token_float | @token_heredoc_beginning | @token_integer | @token_simple_symbol | @unary | @underscore_lhs | @unless | @until | @while | @yield + +@underscore_statement = @alias | @assignment | @begin_block | @binary | @break | @call | @end_block | @if_modifier | @next | @operator_assignment | @rescue_modifier | @return | @unary | @undef | @underscore_arg | @unless_modifier | @until_modifier | @while_modifier | @yield + +@underscore_variable = @token_class_variable | @token_constant | @token_global_variable | @token_identifier | @token_instance_variable | @token_self | @token_super + +alias_def( + unique int id: @alias, + int alias: @underscore_method_name ref, + int name: @underscore_method_name ref, + int loc: @location ref +); + +@argument_list_child_type = @block_argument | @break | @call | @hash_splat_argument | @next | @pair | @return | @splat_argument | @underscore_arg | @yield + +#keyset[argument_list, index] +argument_list_child( + int argument_list: @argument_list ref, + int index: int ref, + unique int child: @argument_list_child_type ref +); + +argument_list_def( + unique int id: @argument_list, + int loc: @location ref +); + +@array_child_type = @block_argument | @break | @call | @hash_splat_argument | @next | @pair | @return | @splat_argument | @underscore_arg | @yield + +#keyset[array, index] +array_child( + int array: @array ref, + int index: int ref, + unique int child: @array_child_type ref +); + +array_def( + unique int id: @array, + int loc: @location ref +); + +@assignment_left_type = @left_assignment_list | @underscore_lhs + +@assignment_right_type = @break | @call | @next | @return | @right_assignment_list | @splat_argument | @underscore_arg | @yield + +assignment_def( + unique int id: @assignment, + int left: @assignment_left_type ref, + int right: @assignment_right_type ref, + int loc: @location ref +); + +@bare_string_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[bare_string, index] +bare_string_child( + int bare_string: @bare_string ref, + int index: int ref, + unique int child: @bare_string_child_type ref +); + +bare_string_def( + unique int id: @bare_string, + int loc: @location ref +); + +@bare_symbol_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[bare_symbol, index] +bare_symbol_child( + int bare_symbol: @bare_symbol ref, + int index: int ref, + unique int child: @bare_symbol_child_type ref +); + +bare_symbol_def( + unique int id: @bare_symbol, + int loc: @location ref +); + +@begin_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[begin, index] +begin_child( + int begin: @begin ref, + int index: int ref, + unique int child: @begin_child_type ref +); + +begin_def( + unique int id: @begin, + int loc: @location ref +); + +@begin_block_child_type = @token_empty_statement | @underscore_statement + +#keyset[begin_block, index] +begin_block_child( + int begin_block: @begin_block ref, + int index: int ref, + unique int child: @begin_block_child_type ref +); + +begin_block_def( + unique int id: @begin_block, + int loc: @location ref +); + +@binary_left_type = @break | @call | @next | @return | @underscore_arg | @yield + +case @binary.operator of + 0 = @binary_bangequal +| 1 = @binary_bangtilde +| 2 = @binary_percent +| 3 = @binary_ampersand +| 4 = @binary_ampersandampersand +| 5 = @binary_star +| 6 = @binary_starstar +| 7 = @binary_plus +| 8 = @binary_minus +| 9 = @binary_slash +| 10 = @binary_langle +| 11 = @binary_langlelangle +| 12 = @binary_langleequal +| 13 = @binary_langleequalrangle +| 14 = @binary_equalequal +| 15 = @binary_equalequalequal +| 16 = @binary_equaltilde +| 17 = @binary_rangle +| 18 = @binary_rangleequal +| 19 = @binary_ranglerangle +| 20 = @binary_caret +| 21 = @binary_and +| 22 = @binary_or +| 23 = @binary_pipe +| 24 = @binary_pipepipe +; + + +@binary_right_type = @break | @call | @next | @return | @underscore_arg | @yield + +binary_def( + unique int id: @binary, + int left: @binary_left_type ref, + int operator: int ref, + int right: @binary_right_type ref, + int loc: @location ref +); + +block_parameters( + unique int block: @block ref, + unique int parameters: @block_parameters ref +); + +@block_child_type = @token_empty_statement | @underscore_statement + +#keyset[block, index] +block_child( + int block: @block ref, + int index: int ref, + unique int child: @block_child_type ref +); + +block_def( + unique int id: @block, + int loc: @location ref +); + +block_argument_def( + unique int id: @block_argument, + int child: @underscore_arg ref, + int loc: @location ref +); + +block_parameter_def( + unique int id: @block_parameter, + int name: @token_identifier ref, + int loc: @location ref +); + +@block_parameters_child_type = @block_parameter | @destructured_parameter | @hash_splat_parameter | @keyword_parameter | @optional_parameter | @splat_parameter | @token_identifier + +#keyset[block_parameters, index] +block_parameters_child( + int block_parameters: @block_parameters ref, + int index: int ref, + unique int child: @block_parameters_child_type ref +); + +block_parameters_def( + unique int id: @block_parameters, + int loc: @location ref +); + +break_child( + unique int break: @break ref, + unique int child: @argument_list ref +); + +break_def( + unique int id: @break, + int loc: @location ref +); + +call_arguments( + unique int call: @call ref, + unique int arguments: @argument_list ref +); + +@call_block_type = @block | @do_block + +call_block( + unique int call: @call ref, + unique int block: @call_block_type ref +); + +@call_method_type = @argument_list | @scope_resolution | @token_operator | @underscore_variable + +@call_receiver_type = @call | @underscore_primary + +call_receiver( + unique int call: @call ref, + unique int receiver: @call_receiver_type ref +); + +call_def( + unique int id: @call, + int method: @call_method_type ref, + int loc: @location ref +); + +case_value( + unique int case__: @case__ ref, + unique int value: @underscore_statement ref +); + +@case_child_type = @else | @when + +#keyset[case__, index] +case_child( + int case__: @case__ ref, + int index: int ref, + unique int child: @case_child_type ref +); + +case_def( + unique int id: @case__, + int loc: @location ref +); + +#keyset[chained_string, index] +chained_string_child( + int chained_string: @chained_string ref, + int index: int ref, + unique int child: @string__ ref +); + +chained_string_def( + unique int id: @chained_string, + int loc: @location ref +); + +@class_name_type = @scope_resolution | @token_constant + +class_superclass( + unique int class: @class ref, + unique int superclass: @superclass ref +); + +@class_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[class, index] +class_child( + int class: @class ref, + int index: int ref, + unique int child: @class_child_type ref +); + +class_def( + unique int id: @class, + int name: @class_name_type ref, + int loc: @location ref +); + +conditional_def( + unique int id: @conditional, + int alternative: @underscore_arg ref, + int condition: @underscore_arg ref, + int consequence: @underscore_arg ref, + int loc: @location ref +); + +@delimited_symbol_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[delimited_symbol, index] +delimited_symbol_child( + int delimited_symbol: @delimited_symbol ref, + int index: int ref, + unique int child: @delimited_symbol_child_type ref +); + +delimited_symbol_def( + unique int id: @delimited_symbol, + int loc: @location ref +); + +@destructured_left_assignment_child_type = @destructured_left_assignment | @rest_assignment | @underscore_lhs + +#keyset[destructured_left_assignment, index] +destructured_left_assignment_child( + int destructured_left_assignment: @destructured_left_assignment ref, + int index: int ref, + unique int child: @destructured_left_assignment_child_type ref +); + +destructured_left_assignment_def( + unique int id: @destructured_left_assignment, + int loc: @location ref +); + +@destructured_parameter_child_type = @block_parameter | @destructured_parameter | @hash_splat_parameter | @keyword_parameter | @optional_parameter | @splat_parameter | @token_identifier + +#keyset[destructured_parameter, index] +destructured_parameter_child( + int destructured_parameter: @destructured_parameter ref, + int index: int ref, + unique int child: @destructured_parameter_child_type ref +); + +destructured_parameter_def( + unique int id: @destructured_parameter, + int loc: @location ref +); + +@do_child_type = @token_empty_statement | @underscore_statement + +#keyset[do, index] +do_child( + int do: @do ref, + int index: int ref, + unique int child: @do_child_type ref +); + +do_def( + unique int id: @do, + int loc: @location ref +); + +do_block_parameters( + unique int do_block: @do_block ref, + unique int parameters: @block_parameters ref +); + +@do_block_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[do_block, index] +do_block_child( + int do_block: @do_block ref, + int index: int ref, + unique int child: @do_block_child_type ref +); + +do_block_def( + unique int id: @do_block, + int loc: @location ref +); + +@element_reference_child_type = @block_argument | @break | @call | @hash_splat_argument | @next | @pair | @return | @splat_argument | @underscore_arg | @yield + +#keyset[element_reference, index] +element_reference_child( + int element_reference: @element_reference ref, + int index: int ref, + unique int child: @element_reference_child_type ref +); + +element_reference_def( + unique int id: @element_reference, + int object: @underscore_primary ref, + int loc: @location ref +); + +@else_child_type = @token_empty_statement | @underscore_statement + +#keyset[else, index] +else_child( + int else: @else ref, + int index: int ref, + unique int child: @else_child_type ref +); + +else_def( + unique int id: @else, + int loc: @location ref +); + +@elsif_alternative_type = @else | @elsif + +elsif_alternative( + unique int elsif: @elsif ref, + unique int alternative: @elsif_alternative_type ref +); + +elsif_consequence( + unique int elsif: @elsif ref, + unique int consequence: @then ref +); + +elsif_def( + unique int id: @elsif, + int condition: @underscore_statement ref, + int loc: @location ref +); + +@end_block_child_type = @token_empty_statement | @underscore_statement + +#keyset[end_block, index] +end_block_child( + int end_block: @end_block ref, + int index: int ref, + unique int child: @end_block_child_type ref +); + +end_block_def( + unique int id: @end_block, + int loc: @location ref +); + +@ensure_child_type = @token_empty_statement | @underscore_statement + +#keyset[ensure, index] +ensure_child( + int ensure: @ensure ref, + int index: int ref, + unique int child: @ensure_child_type ref +); + +ensure_def( + unique int id: @ensure, + int loc: @location ref +); + +exception_variable_def( + unique int id: @exception_variable, + int child: @underscore_lhs ref, + int loc: @location ref +); + +@exceptions_child_type = @splat_argument | @underscore_arg + +#keyset[exceptions, index] +exceptions_child( + int exceptions: @exceptions ref, + int index: int ref, + unique int child: @exceptions_child_type ref +); + +exceptions_def( + unique int id: @exceptions, + int loc: @location ref +); + +@for_pattern_type = @left_assignment_list | @underscore_lhs + +for_def( + unique int id: @for, + int body: @do ref, + int pattern: @for_pattern_type ref, + int value: @in ref, + int loc: @location ref +); + +@hash_child_type = @hash_splat_argument | @pair + +#keyset[hash, index] +hash_child( + int hash: @hash ref, + int index: int ref, + unique int child: @hash_child_type ref +); + +hash_def( + unique int id: @hash, + int loc: @location ref +); + +hash_splat_argument_def( + unique int id: @hash_splat_argument, + int child: @underscore_arg ref, + int loc: @location ref +); + +hash_splat_parameter_name( + unique int hash_splat_parameter: @hash_splat_parameter ref, + unique int name: @token_identifier ref +); + +hash_splat_parameter_def( + unique int id: @hash_splat_parameter, + int loc: @location ref +); + +@heredoc_body_child_type = @interpolation | @token_escape_sequence | @token_heredoc_content | @token_heredoc_end + +#keyset[heredoc_body, index] +heredoc_body_child( + int heredoc_body: @heredoc_body ref, + int index: int ref, + unique int child: @heredoc_body_child_type ref +); + +heredoc_body_def( + unique int id: @heredoc_body, + int loc: @location ref +); + +@if_alternative_type = @else | @elsif + +if_alternative( + unique int if: @if ref, + unique int alternative: @if_alternative_type ref +); + +if_consequence( + unique int if: @if ref, + unique int consequence: @then ref +); + +if_def( + unique int id: @if, + int condition: @underscore_statement ref, + int loc: @location ref +); + +@if_modifier_condition_type = @break | @call | @next | @return | @underscore_arg | @yield + +if_modifier_def( + unique int id: @if_modifier, + int body: @underscore_statement ref, + int condition: @if_modifier_condition_type ref, + int loc: @location ref +); + +in_def( + unique int id: @in, + int child: @underscore_arg ref, + int loc: @location ref +); + +@interpolation_child_type = @token_empty_statement | @underscore_statement + +#keyset[interpolation, index] +interpolation_child( + int interpolation: @interpolation ref, + int index: int ref, + unique int child: @interpolation_child_type ref +); + +interpolation_def( + unique int id: @interpolation, + int loc: @location ref +); + +keyword_parameter_value( + unique int keyword_parameter: @keyword_parameter ref, + unique int value: @underscore_arg ref +); + +keyword_parameter_def( + unique int id: @keyword_parameter, + int name: @token_identifier ref, + int loc: @location ref +); + +@lambda_body_type = @block | @do_block + +lambda_parameters( + unique int lambda: @lambda ref, + unique int parameters: @lambda_parameters ref +); + +lambda_def( + unique int id: @lambda, + int body: @lambda_body_type ref, + int loc: @location ref +); + +@lambda_parameters_child_type = @block_parameter | @destructured_parameter | @hash_splat_parameter | @keyword_parameter | @optional_parameter | @splat_parameter | @token_identifier + +#keyset[lambda_parameters, index] +lambda_parameters_child( + int lambda_parameters: @lambda_parameters ref, + int index: int ref, + unique int child: @lambda_parameters_child_type ref +); + +lambda_parameters_def( + unique int id: @lambda_parameters, + int loc: @location ref +); + +@left_assignment_list_child_type = @destructured_left_assignment | @rest_assignment | @underscore_lhs + +#keyset[left_assignment_list, index] +left_assignment_list_child( + int left_assignment_list: @left_assignment_list ref, + int index: int ref, + unique int child: @left_assignment_list_child_type ref +); + +left_assignment_list_def( + unique int id: @left_assignment_list, + int loc: @location ref +); + +method_parameters( + unique int method: @method ref, + unique int parameters: @method_parameters ref +); + +@method_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[method, index] +method_child( + int method: @method ref, + int index: int ref, + unique int child: @method_child_type ref +); + +method_def( + unique int id: @method, + int name: @underscore_method_name ref, + int loc: @location ref +); + +@method_parameters_child_type = @block_parameter | @destructured_parameter | @hash_splat_parameter | @keyword_parameter | @optional_parameter | @splat_parameter | @token_identifier + +#keyset[method_parameters, index] +method_parameters_child( + int method_parameters: @method_parameters ref, + int index: int ref, + unique int child: @method_parameters_child_type ref +); + +method_parameters_def( + unique int id: @method_parameters, + int loc: @location ref +); + +@module_name_type = @scope_resolution | @token_constant + +@module_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[module, index] +module_child( + int module: @module ref, + int index: int ref, + unique int child: @module_child_type ref +); + +module_def( + unique int id: @module, + int name: @module_name_type ref, + int loc: @location ref +); + +next_child( + unique int next: @next ref, + unique int child: @argument_list ref +); + +next_def( + unique int id: @next, + int loc: @location ref +); + +case @operator_assignment.operator of + 0 = @operator_assignment_percentequal +| 1 = @operator_assignment_ampersandampersandequal +| 2 = @operator_assignment_ampersandequal +| 3 = @operator_assignment_starstarequal +| 4 = @operator_assignment_starequal +| 5 = @operator_assignment_plusequal +| 6 = @operator_assignment_minusequal +| 7 = @operator_assignment_slashequal +| 8 = @operator_assignment_langlelangleequal +| 9 = @operator_assignment_ranglerangleequal +| 10 = @operator_assignment_caretequal +| 11 = @operator_assignment_pipeequal +| 12 = @operator_assignment_pipepipeequal +; + + +@operator_assignment_right_type = @break | @call | @next | @return | @underscore_arg | @yield + +operator_assignment_def( + unique int id: @operator_assignment, + int left: @underscore_lhs ref, + int operator: int ref, + int right: @operator_assignment_right_type ref, + int loc: @location ref +); + +optional_parameter_def( + unique int id: @optional_parameter, + int name: @token_identifier ref, + int value: @underscore_arg ref, + int loc: @location ref +); + +@pair_key_type = @string__ | @token_hash_key_symbol | @underscore_arg + +pair_def( + unique int id: @pair, + int key__: @pair_key_type ref, + int value: @underscore_arg ref, + int loc: @location ref +); + +@parenthesized_statements_child_type = @token_empty_statement | @underscore_statement + +#keyset[parenthesized_statements, index] +parenthesized_statements_child( + int parenthesized_statements: @parenthesized_statements ref, + int index: int ref, + unique int child: @parenthesized_statements_child_type ref +); + +parenthesized_statements_def( + unique int id: @parenthesized_statements, + int loc: @location ref +); + +@pattern_child_type = @splat_argument | @underscore_arg + +pattern_def( + unique int id: @pattern, + int child: @pattern_child_type ref, + int loc: @location ref +); + +@program_child_type = @token_empty_statement | @token_uninterpreted | @underscore_statement + +#keyset[program, index] +program_child( + int program: @program ref, + int index: int ref, + unique int child: @program_child_type ref +); + +program_def( + unique int id: @program, + int loc: @location ref +); + +range_begin( + unique int range: @range ref, + unique int begin: @underscore_arg ref +); + +range_end( + unique int range: @range ref, + unique int end: @underscore_arg ref +); + +case @range.operator of + 0 = @range_dotdot +| 1 = @range_dotdotdot +; + + +range_def( + unique int id: @range, + int operator: int ref, + int loc: @location ref +); + +@rational_child_type = @token_float | @token_integer + +rational_def( + unique int id: @rational, + int child: @rational_child_type ref, + int loc: @location ref +); + +redo_child( + unique int redo: @redo ref, + unique int child: @argument_list ref +); + +redo_def( + unique int id: @redo, + int loc: @location ref +); + +@regex_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[regex, index] +regex_child( + int regex: @regex ref, + int index: int ref, + unique int child: @regex_child_type ref +); + +regex_def( + unique int id: @regex, + int loc: @location ref +); + +rescue_body( + unique int rescue: @rescue ref, + unique int body: @then ref +); + +rescue_exceptions( + unique int rescue: @rescue ref, + unique int exceptions: @exceptions ref +); + +rescue_variable( + unique int rescue: @rescue ref, + unique int variable: @exception_variable ref +); + +rescue_def( + unique int id: @rescue, + int loc: @location ref +); + +@rescue_modifier_handler_type = @break | @call | @next | @return | @underscore_arg | @yield + +rescue_modifier_def( + unique int id: @rescue_modifier, + int body: @underscore_statement ref, + int handler: @rescue_modifier_handler_type ref, + int loc: @location ref +); + +rest_assignment_child( + unique int rest_assignment: @rest_assignment ref, + unique int child: @underscore_lhs ref +); + +rest_assignment_def( + unique int id: @rest_assignment, + int loc: @location ref +); + +retry_child( + unique int retry: @retry ref, + unique int child: @argument_list ref +); + +retry_def( + unique int id: @retry, + int loc: @location ref +); + +return_child( + unique int return: @return ref, + unique int child: @argument_list ref +); + +return_def( + unique int id: @return, + int loc: @location ref +); + +@right_assignment_list_child_type = @splat_argument | @underscore_arg + +#keyset[right_assignment_list, index] +right_assignment_list_child( + int right_assignment_list: @right_assignment_list ref, + int index: int ref, + unique int child: @right_assignment_list_child_type ref +); + +right_assignment_list_def( + unique int id: @right_assignment_list, + int loc: @location ref +); + +@scope_resolution_name_type = @token_constant | @token_identifier + +scope_resolution_scope( + unique int scope_resolution: @scope_resolution ref, + unique int scope: @underscore_primary ref +); + +scope_resolution_def( + unique int id: @scope_resolution, + int name: @scope_resolution_name_type ref, + int loc: @location ref +); + +setter_def( + unique int id: @setter, + int name: @token_identifier ref, + int loc: @location ref +); + +@singleton_class_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[singleton_class, index] +singleton_class_child( + int singleton_class: @singleton_class ref, + int index: int ref, + unique int child: @singleton_class_child_type ref +); + +singleton_class_def( + unique int id: @singleton_class, + int value: @underscore_arg ref, + int loc: @location ref +); + +@singleton_method_object_type = @underscore_arg | @underscore_variable + +singleton_method_parameters( + unique int singleton_method: @singleton_method ref, + unique int parameters: @method_parameters ref +); + +@singleton_method_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement + +#keyset[singleton_method, index] +singleton_method_child( + int singleton_method: @singleton_method ref, + int index: int ref, + unique int child: @singleton_method_child_type ref +); + +singleton_method_def( + unique int id: @singleton_method, + int name: @underscore_method_name ref, + int object: @singleton_method_object_type ref, + int loc: @location ref +); + +splat_argument_def( + unique int id: @splat_argument, + int child: @underscore_arg ref, + int loc: @location ref +); + +splat_parameter_name( + unique int splat_parameter: @splat_parameter ref, + unique int name: @token_identifier ref +); + +splat_parameter_def( + unique int id: @splat_parameter, + int loc: @location ref +); + +@string_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[string__, index] +string_child( + int string__: @string__ ref, + int index: int ref, + unique int child: @string_child_type ref +); + +string_def( + unique int id: @string__, + int loc: @location ref +); + +#keyset[string_array, index] +string_array_child( + int string_array: @string_array ref, + int index: int ref, + unique int child: @bare_string ref +); + +string_array_def( + unique int id: @string_array, + int loc: @location ref +); + +@subshell_child_type = @interpolation | @token_escape_sequence | @token_string_content + +#keyset[subshell, index] +subshell_child( + int subshell: @subshell ref, + int index: int ref, + unique int child: @subshell_child_type ref +); + +subshell_def( + unique int id: @subshell, + int loc: @location ref +); + +@superclass_child_type = @break | @call | @next | @return | @underscore_arg | @yield + +superclass_def( + unique int id: @superclass, + int child: @superclass_child_type ref, + int loc: @location ref +); + +#keyset[symbol_array, index] +symbol_array_child( + int symbol_array: @symbol_array ref, + int index: int ref, + unique int child: @bare_symbol ref +); + +symbol_array_def( + unique int id: @symbol_array, + int loc: @location ref +); + +@then_child_type = @token_empty_statement | @underscore_statement + +#keyset[then, index] +then_child( + int then: @then ref, + int index: int ref, + unique int child: @then_child_type ref +); + +then_def( + unique int id: @then, + int loc: @location ref +); + +@unary_operand_type = @break | @call | @next | @parenthesized_statements | @return | @token_float | @token_integer | @underscore_arg | @yield + +case @unary.operator of + 0 = @unary_bang +| 1 = @unary_plus +| 2 = @unary_minus +| 3 = @unary_definedquestion +| 4 = @unary_not +| 5 = @unary_tilde +; + + +unary_def( + unique int id: @unary, + int operand: @unary_operand_type ref, + int operator: int ref, + int loc: @location ref +); + +#keyset[undef, index] +undef_child( + int undef: @undef ref, + int index: int ref, + unique int child: @underscore_method_name ref +); + +undef_def( + unique int id: @undef, + int loc: @location ref +); + +@unless_alternative_type = @else | @elsif + +unless_alternative( + unique int unless: @unless ref, + unique int alternative: @unless_alternative_type ref +); + +unless_consequence( + unique int unless: @unless ref, + unique int consequence: @then ref +); + +unless_def( + unique int id: @unless, + int condition: @underscore_statement ref, + int loc: @location ref +); + +@unless_modifier_condition_type = @break | @call | @next | @return | @underscore_arg | @yield + +unless_modifier_def( + unique int id: @unless_modifier, + int body: @underscore_statement ref, + int condition: @unless_modifier_condition_type ref, + int loc: @location ref +); + +until_def( + unique int id: @until, + int body: @do ref, + int condition: @underscore_statement ref, + int loc: @location ref +); + +@until_modifier_condition_type = @break | @call | @next | @return | @underscore_arg | @yield + +until_modifier_def( + unique int id: @until_modifier, + int body: @underscore_statement ref, + int condition: @until_modifier_condition_type ref, + int loc: @location ref +); + +when_body( + unique int when: @when ref, + unique int body: @then ref +); + +#keyset[when, index] +when_pattern( + int when: @when ref, + int index: int ref, + unique int pattern: @pattern ref +); + +when_def( + unique int id: @when, + int loc: @location ref +); + +while_def( + unique int id: @while, + int body: @do ref, + int condition: @underscore_statement ref, + int loc: @location ref +); + +@while_modifier_condition_type = @break | @call | @next | @return | @underscore_arg | @yield + +while_modifier_def( + unique int id: @while_modifier, + int body: @underscore_statement ref, + int condition: @while_modifier_condition_type ref, + int loc: @location ref +); + +yield_child( + unique int yield: @yield ref, + unique int child: @argument_list ref +); + +yield_def( + unique int id: @yield, + int loc: @location ref +); + +tokeninfo( + unique int id: @token, + int kind: int ref, + int file: @file ref, + int idx: int ref, + string value: string ref, + int loc: @location ref +); + +case @token.kind of + 0 = @reserved_word +| 1 = @token_character +| 2 = @token_class_variable +| 3 = @token_comment +| 4 = @token_complex +| 5 = @token_constant +| 6 = @token_empty_statement +| 7 = @token_escape_sequence +| 8 = @token_false +| 9 = @token_float +| 10 = @token_global_variable +| 11 = @token_hash_key_symbol +| 12 = @token_heredoc_beginning +| 13 = @token_heredoc_content +| 14 = @token_heredoc_end +| 15 = @token_identifier +| 16 = @token_instance_variable +| 17 = @token_integer +| 18 = @token_nil +| 19 = @token_operator +| 20 = @token_self +| 21 = @token_simple_symbol +| 22 = @token_string_content +| 23 = @token_super +| 24 = @token_true +| 25 = @token_uninterpreted +; + + +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 +; + + +@ast_node = @alias | @argument_list | @array | @assignment | @bare_string | @bare_symbol | @begin | @begin_block | @binary | @block | @block_argument | @block_parameter | @block_parameters | @break | @call | @case__ | @chained_string | @class | @conditional | @delimited_symbol | @destructured_left_assignment | @destructured_parameter | @do | @do_block | @element_reference | @else | @elsif | @end_block | @ensure | @exception_variable | @exceptions | @for | @hash | @hash_splat_argument | @hash_splat_parameter | @heredoc_body | @if | @if_modifier | @in | @interpolation | @keyword_parameter | @lambda | @lambda_parameters | @left_assignment_list | @method | @method_parameters | @module | @next | @operator_assignment | @optional_parameter | @pair | @parenthesized_statements | @pattern | @program | @range | @rational | @redo | @regex | @rescue | @rescue_modifier | @rest_assignment | @retry | @return | @right_assignment_list | @scope_resolution | @setter | @singleton_class | @singleton_method | @splat_argument | @splat_parameter | @string__ | @string_array | @subshell | @superclass | @symbol_array | @then | @token | @unary | @undef | @unless | @unless_modifier | @until | @until_modifier | @when | @while | @while_modifier | @yield + +@ast_node_parent = @ast_node | @file + +#keyset[parent, parent_index] +ast_node_parent( + int child: @ast_node ref, + int parent: @ast_node_parent ref, + int parent_index: int ref +); + diff --git a/upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/upgrade.properties b/upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/upgrade.properties new file mode 100644 index 00000000000..2261e7e5111 --- /dev/null +++ b/upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/upgrade.properties @@ -0,0 +1,2 @@ +description: Create an empty diagnostics table +compatibility: backwards From 15712df717b311357c84c5837876f692be72a734 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 13 May 2021 13:50:53 +0100 Subject: [PATCH 57/66] update ruby.dbscheme.stats --- ql/src/ruby.dbscheme.stats | 8370 +++++++++++++++++++----------------- 1 file changed, 4469 insertions(+), 3901 deletions(-) diff --git a/ql/src/ruby.dbscheme.stats b/ql/src/ruby.dbscheme.stats index f378fd528ce..665de5190c2 100644 --- a/ql/src/ruby.dbscheme.stats +++ b/ql/src/ruby.dbscheme.stats @@ -1,31 +1,31 @@ @alias - 440 + 398 @argument_list - 212901 + 215845 @array - 10207 + 10382 @assignment - 38827 + 39638 @bare_string - 2973 + 3009 @bare_symbol - 667 + 687 @begin - 600 + 613 @begin_block @@ -33,19 +33,19 @@ @binary_ampersand - 40 + 41 @binary_ampersandampersand - 2744 + 2775 @binary_and - 87 + 85 @binary_bangequal - 480 + 498 @binary_bangtilde @@ -57,35 +57,35 @@ @binary_equalequal - 2475 + 2506 @binary_equalequalequal - 174 + 173 @binary_equaltilde - 241 + 237 @binary_langle - 426 + 430 @binary_langleequal - 86 + 84 @binary_langleequalrangle - 82 + 83 @binary_langlelangle - 3253 + 3285 @binary_minus - 619 + 624 @binary_or @@ -93,27 +93,27 @@ @binary_percent - 130 + 140 @binary_pipe - 41 + 42 @binary_pipepipe - 2496 + 2531 @binary_plus - 1469 + 1490 @binary_rangle - 770 + 772 @binary_rangleequal - 127 + 125 @binary_ranglerangle @@ -121,59 +121,59 @@ @binary_slash - 139 + 136 @binary_star - 355 + 364 @binary_starstar - 32 + 33 @block - 20840 + 21214 @block_argument - 1699 + 1770 @block_parameter - 650 + 658 @block_parameters - 7081 + 7227 @break - 210 + 214 @call - 300117 + 303820 @case__ - 370 + 377 @chained_string - 262 + 268 @class - 5115 + 5194 @conditional - 1104 + 1120 @delimited_symbol - 379 + 384 @destructured_left_assignment @@ -181,27 +181,43 @@ @destructured_parameter - 61 + 62 + + + @diagnostic_debug + 0 + + + @diagnostic_error + 64 + + + @diagnostic_info + 0 + + + @diagnostic_warning + 0 @do - 116 + 117 @do_block - 41153 + 41659 @element_reference - 25064 + 25582 @else - 2073 + 2122 @elsif - 474 + 491 @end_block @@ -209,23 +225,23 @@ @ensure - 1152 + 1125 @exception_variable - 298 + 309 @exceptions - 416 + 429 @file - 6179 + 6322 @folder - 1459 + 1489 @for @@ -233,27 +249,27 @@ @hash - 8043 + 8122 @hash_splat_argument - 369 + 398 @hash_splat_parameter - 402 + 413 @heredoc_body - 1567 + 1610 @if - 5609 + 5713 @if_modifier - 4182 + 4276 @in @@ -261,43 +277,43 @@ @interpolation - 11532 + 11773 @keyword_parameter - 1006 + 1099 @lambda - 636 + 660 @lambda_parameters - 184 + 190 @left_assignment_list - 762 + 773 @location_default - 2557616 + 2604972 @method - 29945 + 30455 @method_parameters - 8700 + 8920 @module - 4029 + 4441 @next - 620 + 653 @operator_assignment_ampersandampersandequal @@ -325,15 +341,15 @@ @operator_assignment_pipeequal - 42 + 44 @operator_assignment_pipepipeequal - 1410 + 1417 @operator_assignment_plusequal - 483 + 506 @operator_assignment_ranglerangleequal @@ -353,27 +369,27 @@ @optional_parameter - 2031 + 2047 @pair - 59815 + 62127 @parenthesized_statements - 1646 + 1652 @pattern - 1171 + 1186 @program - 6179 + 6322 @range_dotdot - 416 + 424 @range_dotdotdot @@ -389,23 +405,23 @@ @regex - 3949 + 3979 @rescue - 616 + 634 @rescue_modifier - 171 + 174 @reserved_word - 991410 + 1009882 @rest_assignment - 17 + 18 @retry @@ -413,59 +429,59 @@ @return - 2548 + 2601 @right_assignment_list - 407 + 414 @scope_resolution - 22240 + 22918 @setter - 181 + 186 @singleton_class - 185 + 191 @singleton_method - 1996 + 2020 @splat_argument - 693 + 683 @splat_parameter - 932 + 921 @string__ - 89867 + 91253 @string_array - 929 + 938 @subshell - 129 + 130 @superclass - 4039 + 4108 @symbol_array - 136 + 139 @then - 7463 + 7609 @token_character @@ -473,11 +489,11 @@ @token_class_variable - 244 + 238 @token_comment - 55267 + 55974 @token_complex @@ -485,7 +501,7 @@ @token_constant - 84940 + 86706 @token_empty_statement @@ -493,91 +509,91 @@ @token_escape_sequence - 19870 + 19932 @token_false - 5070 + 5175 @token_float - 3177 + 3122 @token_global_variable - 730 + 724 @token_hash_key_symbol - 58363 + 60562 @token_heredoc_beginning - 1567 + 1610 @token_heredoc_content - 3548 + 3662 @token_heredoc_end - 1567 + 1610 @token_identifier - 450490 + 456774 @token_instance_variable - 24563 + 25234 @token_integer - 32109 + 32694 @token_nil - 3988 + 4047 @token_operator - 189 + 195 @token_self - 3943 + 4040 @token_simple_symbol - 81015 + 82353 @token_string_content - 113680 + 115192 @token_super - 1522 + 1554 @token_true - 7163 + 7308 @token_uninterpreted 0 - + @unary_bang - 1632 + 1682 @unary_definedquestion - 309 + 247 @unary_minus - 631 + 651 @unary_not @@ -597,15 +613,15 @@ @unless - 481 + 497 @unless_modifier - 1396 + 1404 @until - 14 + 16 @until_modifier @@ -613,40 +629,40 @@ @when - 970 + 987 @while - 104 + 106 @while_modifier - 8 + 9 @yield - 836 + 841 alias_def - 440 + 398 id - 440 + 398 alias - 440 + 398 name - 440 + 398 loc - 440 + 398 @@ -660,7 +676,7 @@ 1 2 - 440 + 398 @@ -676,7 +692,7 @@ 1 2 - 440 + 398 @@ -692,7 +708,7 @@ 1 2 - 440 + 398 @@ -708,7 +724,7 @@ 1 2 - 440 + 398 @@ -724,7 +740,7 @@ 1 2 - 440 + 398 @@ -740,7 +756,7 @@ 1 2 - 440 + 398 @@ -756,7 +772,7 @@ 1 2 - 440 + 398 @@ -772,7 +788,7 @@ 1 2 - 440 + 398 @@ -788,7 +804,7 @@ 1 2 - 440 + 398 @@ -804,7 +820,7 @@ 1 2 - 440 + 398 @@ -820,7 +836,7 @@ 1 2 - 440 + 398 @@ -836,7 +852,7 @@ 1 2 - 440 + 398 @@ -846,19 +862,19 @@ argument_list_child - 272095 + 276770 argument_list - 212831 + 215777 index - 111 + 109 child - 272095 + 276770 @@ -872,17 +888,17 @@ 1 2 - 173999 + 176126 2 3 - 26248 + 26678 3 33 - 12583 + 12972 @@ -898,17 +914,17 @@ 1 2 - 173999 + 176126 2 3 - 26248 + 26678 3 33 - 12583 + 12972 @@ -924,7 +940,7 @@ 1 2 - 38 + 37 2 @@ -943,42 +959,42 @@ 5 - 6 + 8 6 - 8 - 11 + 9 + 12 6 - 13 - 16 + 14 + 17 6 - 19 - 37 + 24 + 43 6 - 93 - 219 + 103 + 235 6 - 485 - 1314 + 535 + 1428 6 - 3604 - 11123 + 3806 + 11634 6 - 60958 - 60959 + 63305 + 63306 3 @@ -995,7 +1011,7 @@ 1 2 - 38 + 37 2 @@ -1014,42 +1030,42 @@ 5 - 6 + 8 6 - 8 - 11 + 9 + 12 6 - 13 - 16 + 14 + 17 6 - 19 - 37 + 24 + 43 6 - 93 - 219 + 103 + 235 6 - 485 - 1314 + 535 + 1428 6 - 3604 - 11123 + 3806 + 11634 6 - 60958 - 60959 + 63305 + 63306 3 @@ -1066,7 +1082,7 @@ 1 2 - 272095 + 276770 @@ -1082,7 +1098,7 @@ 1 2 - 272095 + 276770 @@ -1092,15 +1108,15 @@ argument_list_def - 212901 + 215845 id - 212901 + 215845 loc - 212901 + 215845 @@ -1114,7 +1130,7 @@ 1 2 - 212901 + 215845 @@ -1130,7 +1146,7 @@ 1 2 - 212901 + 215845 @@ -1140,11 +1156,11 @@ array_child - 19321 + 19631 array - 8617 + 8772 index @@ -1152,7 +1168,7 @@ child - 19321 + 19631 @@ -1166,22 +1182,22 @@ 1 2 - 2849 + 2906 2 3 - 3729 + 3796 3 4 - 1249 + 1270 4 9 - 657 + 667 9 @@ -1202,22 +1218,22 @@ 1 2 - 2849 + 2906 2 3 - 3729 + 3796 3 4 - 1249 + 1270 4 9 - 657 + 667 9 @@ -1276,13 +1292,13 @@ 7 - 168 - 5769 + 169 + 5867 7 - 8617 - 8618 + 8772 + 8773 1 @@ -1337,13 +1353,13 @@ 7 - 168 - 5769 + 169 + 5867 7 - 8617 - 8618 + 8772 + 8773 1 @@ -1360,7 +1376,7 @@ 1 2 - 19321 + 19631 @@ -1376,7 +1392,7 @@ 1 2 - 19321 + 19631 @@ -1386,15 +1402,15 @@ array_def - 10207 + 10382 id - 10207 + 10382 loc - 10207 + 10382 @@ -1408,7 +1424,7 @@ 1 2 - 10207 + 10382 @@ -1424,7 +1440,7 @@ 1 2 - 10207 + 10382 @@ -1434,23 +1450,23 @@ assignment_def - 38827 + 39638 id - 38827 + 39638 left - 38827 + 39638 right - 38827 + 39638 loc - 38827 + 39638 @@ -1464,7 +1480,7 @@ 1 2 - 38827 + 39638 @@ -1480,7 +1496,7 @@ 1 2 - 38827 + 39638 @@ -1496,7 +1512,7 @@ 1 2 - 38827 + 39638 @@ -1512,7 +1528,7 @@ 1 2 - 38827 + 39638 @@ -1528,7 +1544,7 @@ 1 2 - 38827 + 39638 @@ -1544,7 +1560,7 @@ 1 2 - 38827 + 39638 @@ -1560,7 +1576,7 @@ 1 2 - 38827 + 39638 @@ -1576,7 +1592,7 @@ 1 2 - 38827 + 39638 @@ -1592,7 +1608,7 @@ 1 2 - 38827 + 39638 @@ -1608,7 +1624,7 @@ 1 2 - 38827 + 39638 @@ -1624,7 +1640,7 @@ 1 2 - 38827 + 39638 @@ -1640,7 +1656,7 @@ 1 2 - 38827 + 39638 @@ -1650,19 +1666,19 @@ ast_node_parent - 2640772 + 2689484 child - 2640772 + 2689484 parent - 867233 + 882787 parent_index - 597 + 586 @@ -1676,7 +1692,7 @@ 1 2 - 2640772 + 2689484 @@ -1692,7 +1708,7 @@ 1 2 - 2640772 + 2689484 @@ -1708,27 +1724,27 @@ 1 2 - 94282 + 95994 2 3 - 126484 + 128409 3 4 - 467392 + 476622 4 5 - 114100 + 115559 5 - 172 - 64972 + 173 + 66200 @@ -1744,27 +1760,27 @@ 1 2 - 94282 + 95994 2 3 - 126484 + 128409 3 4 - 467392 + 476622 4 5 - 114100 + 115559 5 - 172 - 64972 + 173 + 66200 @@ -1780,57 +1796,57 @@ 1 2 - 125 + 126 2 3 - 90 + 68 3 4 - 34 + 54 4 5 - 27 + 13 5 - 8 - 45 + 7 + 51 - 8 - 14 - 45 + 7 + 15 + 51 - 14 - 25 - 45 + 15 + 27 + 47 - 25 - 52 - 45 + 28 + 58 + 44 - 54 - 129 - 45 + 61 + 147 + 44 - 139 - 638 - 45 + 161 + 923 + 44 - 868 - 248389 - 45 + 1058 + 258994 + 40 @@ -1846,57 +1862,57 @@ 1 2 - 125 + 126 2 3 - 90 + 68 3 4 - 34 + 54 4 5 - 27 + 13 5 - 8 - 45 + 7 + 51 - 8 - 14 - 45 + 7 + 15 + 51 - 14 - 25 - 45 + 15 + 27 + 47 - 25 - 52 - 45 + 28 + 58 + 44 - 54 - 129 - 45 + 61 + 147 + 44 - 139 - 638 - 45 + 161 + 923 + 44 - 868 - 248389 - 45 + 1058 + 258994 + 40 @@ -1906,11 +1922,11 @@ bare_string_child - 2982 + 3021 bare_string - 2973 + 3009 index @@ -1918,7 +1934,7 @@ child - 2982 + 3021 @@ -1932,12 +1948,12 @@ 1 2 - 2964 + 2997 2 3 - 9 + 12 @@ -1953,12 +1969,12 @@ 1 2 - 2964 + 2997 2 3 - 9 + 12 @@ -1972,13 +1988,13 @@ 12 - 9 - 10 + 12 + 13 1 - 2973 - 2974 + 3009 + 3010 1 @@ -1993,13 +2009,13 @@ 12 - 9 - 10 + 12 + 13 1 - 2973 - 2974 + 3009 + 3010 1 @@ -2016,7 +2032,7 @@ 1 2 - 2982 + 3021 @@ -2032,7 +2048,7 @@ 1 2 - 2982 + 3021 @@ -2042,15 +2058,15 @@ bare_string_def - 2973 + 3009 id - 2973 + 3009 loc - 2973 + 3009 @@ -2064,7 +2080,7 @@ 1 2 - 2973 + 3009 @@ -2080,7 +2096,7 @@ 1 2 - 2973 + 3009 @@ -2090,11 +2106,11 @@ bare_symbol_child - 667 + 687 bare_symbol - 667 + 687 index @@ -2102,7 +2118,7 @@ child - 667 + 687 @@ -2116,7 +2132,7 @@ 1 2 - 667 + 687 @@ -2132,7 +2148,7 @@ 1 2 - 667 + 687 @@ -2146,8 +2162,8 @@ 12 - 649 - 650 + 672 + 673 1 @@ -2162,8 +2178,8 @@ 12 - 649 - 650 + 672 + 673 1 @@ -2180,7 +2196,7 @@ 1 2 - 667 + 687 @@ -2196,7 +2212,7 @@ 1 2 - 667 + 687 @@ -2206,15 +2222,15 @@ bare_symbol_def - 667 + 687 id - 667 + 687 loc - 667 + 687 @@ -2228,7 +2244,7 @@ 1 2 - 667 + 687 @@ -2244,7 +2260,7 @@ 1 2 - 667 + 687 @@ -2388,11 +2404,11 @@ begin_child - 2058 + 2106 begin - 600 + 613 index @@ -2400,7 +2416,7 @@ child - 2058 + 2106 @@ -2414,37 +2430,37 @@ 1 2 - 30 + 31 2 3 - 270 + 278 3 4 - 128 + 126 4 5 - 65 + 68 5 7 - 51 + 52 7 13 - 45 + 46 13 35 - 8 + 9 @@ -2460,37 +2476,37 @@ 1 2 - 30 + 31 2 3 - 270 + 278 3 4 - 128 + 126 4 5 - 65 + 68 5 7 - 51 + 52 7 13 - 45 + 46 13 35 - 8 + 9 @@ -2515,27 +2531,27 @@ 5 - 11 + 12 3 - 13 - 28 + 14 + 30 3 - 38 - 72 + 41 + 74 3 - 102 - 292 + 105 + 297 3 - 554 - 585 + 568 + 600 2 @@ -2561,27 +2577,27 @@ 5 - 11 + 12 3 - 13 - 28 + 14 + 30 3 - 38 - 72 + 41 + 74 3 - 102 - 292 + 105 + 297 3 - 554 - 585 + 568 + 600 2 @@ -2598,7 +2614,7 @@ 1 2 - 2058 + 2106 @@ -2614,7 +2630,7 @@ 1 2 - 2058 + 2106 @@ -2624,15 +2640,15 @@ begin_def - 600 + 613 id - 600 + 613 loc - 600 + 613 @@ -2646,7 +2662,7 @@ 1 2 - 600 + 613 @@ -2662,7 +2678,7 @@ 1 2 - 600 + 613 @@ -2672,15 +2688,15 @@ binary_def - 13823 + 13969 id - 13823 + 13969 left - 13823 + 13969 operator @@ -2688,11 +2704,11 @@ right - 13823 + 13969 loc - 13823 + 13969 @@ -2706,7 +2722,7 @@ 1 2 - 13823 + 13969 @@ -2722,7 +2738,7 @@ 1 2 - 13823 + 13969 @@ -2738,7 +2754,7 @@ 1 2 - 13823 + 13969 @@ -2754,7 +2770,7 @@ 1 2 - 13823 + 13969 @@ -2770,7 +2786,7 @@ 1 2 - 13823 + 13969 @@ -2786,7 +2802,7 @@ 1 2 - 13823 + 13969 @@ -2802,7 +2818,7 @@ 1 2 - 13823 + 13969 @@ -2818,7 +2834,7 @@ 1 2 - 13823 + 13969 @@ -2847,49 +2863,54 @@ 1 - 35 - 36 + 36 + 37 2 - 84 - 97 + 83 + 98 2 - 112 - 122 + 114 + 115 + 1 + + + 123 + 124 2 - 124 - 236 + 232 + 303 2 - 302 - 416 + 421 + 488 2 - 467 - 603 + 610 + 756 2 - 749 - 1141 + 1172 + 1377 2 - 1373 - 2408 + 2448 + 2474 2 - 2427 - 2669 - 2 + 2711 + 2712 + 1 @@ -2918,49 +2939,54 @@ 1 - 35 - 36 + 36 + 37 2 - 84 - 97 + 83 + 98 2 - 112 - 122 + 114 + 115 + 1 + + + 123 + 124 2 - 124 - 236 + 232 + 303 2 - 302 - 416 + 421 + 488 2 - 467 - 603 + 610 + 756 2 - 749 - 1141 + 1172 + 1377 2 - 1373 - 2408 + 2448 + 2474 2 - 2427 - 2669 - 2 + 2711 + 2712 + 1 @@ -2989,49 +3015,54 @@ 1 - 35 - 36 + 36 + 37 2 - 84 - 97 + 83 + 98 2 - 112 - 122 + 114 + 115 + 1 + + + 123 + 124 2 - 124 - 236 + 232 + 303 2 - 302 - 416 + 421 + 488 2 - 467 - 603 + 610 + 756 2 - 749 - 1141 + 1172 + 1377 2 - 1373 - 2408 + 2448 + 2474 2 - 2427 - 2669 - 2 + 2711 + 2712 + 1 @@ -3060,49 +3091,54 @@ 1 - 35 - 36 + 36 + 37 2 - 84 - 97 + 83 + 98 2 - 112 - 122 + 114 + 115 + 1 + + + 123 + 124 2 - 124 - 236 + 232 + 303 2 - 302 - 416 + 421 + 488 2 - 467 - 603 + 610 + 756 2 - 749 - 1141 + 1172 + 1377 2 - 1373 - 2408 + 2448 + 2474 2 - 2427 - 2669 - 2 + 2711 + 2712 + 1 @@ -3118,7 +3154,7 @@ 1 2 - 13823 + 13969 @@ -3134,7 +3170,7 @@ 1 2 - 13823 + 13969 @@ -3150,7 +3186,7 @@ 1 2 - 13823 + 13969 @@ -3166,7 +3202,7 @@ 1 2 - 13823 + 13969 @@ -3182,7 +3218,7 @@ 1 2 - 13823 + 13969 @@ -3198,7 +3234,7 @@ 1 2 - 13823 + 13969 @@ -3214,7 +3250,7 @@ 1 2 - 13823 + 13969 @@ -3230,7 +3266,7 @@ 1 2 - 13823 + 13969 @@ -3240,19 +3276,19 @@ block_argument_def - 1699 + 1770 id - 1699 + 1770 child - 1699 + 1770 loc - 1699 + 1770 @@ -3266,7 +3302,7 @@ 1 2 - 1699 + 1770 @@ -3282,7 +3318,7 @@ 1 2 - 1699 + 1770 @@ -3298,7 +3334,7 @@ 1 2 - 1699 + 1770 @@ -3314,7 +3350,7 @@ 1 2 - 1699 + 1770 @@ -3330,7 +3366,7 @@ 1 2 - 1699 + 1770 @@ -3346,7 +3382,7 @@ 1 2 - 1699 + 1770 @@ -3356,11 +3392,11 @@ block_child - 20829 + 21204 block - 20791 + 21163 index @@ -3368,7 +3404,7 @@ child - 20829 + 21204 @@ -3382,12 +3418,12 @@ 1 2 - 20767 + 21136 2 5 - 24 + 27 @@ -3403,12 +3439,12 @@ 1 2 - 20767 + 21136 2 5 - 24 + 27 @@ -3432,13 +3468,13 @@ 3 - 7 - 8 + 8 + 9 3 - 5955 - 5956 + 6209 + 6210 3 @@ -3463,13 +3499,13 @@ 3 - 7 - 8 + 8 + 9 3 - 5955 - 5956 + 6209 + 6210 3 @@ -3486,7 +3522,7 @@ 1 2 - 20829 + 21204 @@ -3502,7 +3538,7 @@ 1 2 - 20829 + 21204 @@ -3512,15 +3548,15 @@ block_def - 20840 + 21214 id - 20840 + 21214 loc - 20840 + 21214 @@ -3534,7 +3570,7 @@ 1 2 - 20840 + 21214 @@ -3550,7 +3586,7 @@ 1 2 - 20840 + 21214 @@ -3560,19 +3596,19 @@ block_parameter_def - 650 + 658 id - 650 + 658 name - 650 + 658 loc - 650 + 658 @@ -3586,7 +3622,7 @@ 1 2 - 650 + 658 @@ -3602,7 +3638,7 @@ 1 2 - 650 + 658 @@ -3618,7 +3654,7 @@ 1 2 - 650 + 658 @@ -3634,7 +3670,7 @@ 1 2 - 650 + 658 @@ -3650,7 +3686,7 @@ 1 2 - 650 + 658 @@ -3666,7 +3702,7 @@ 1 2 - 650 + 658 @@ -3676,15 +3712,15 @@ block_parameters - 2630 + 2662 block - 2630 + 2662 parameters - 2630 + 2662 @@ -3698,7 +3734,7 @@ 1 2 - 2630 + 2662 @@ -3714,7 +3750,7 @@ 1 2 - 2630 + 2662 @@ -3724,11 +3760,11 @@ block_parameters_child - 8262 + 8428 block_parameters - 7081 + 7227 index @@ -3736,7 +3772,7 @@ child - 8262 + 8428 @@ -3750,17 +3786,17 @@ 1 2 - 6041 + 6166 2 3 - 941 + 963 3 6 - 99 + 98 @@ -3776,17 +3812,17 @@ 1 2 - 6041 + 6166 2 3 - 941 + 963 3 6 - 99 + 98 @@ -3810,18 +3846,18 @@ 1 - 99 - 100 + 98 + 99 1 - 1040 - 1041 + 1061 + 1062 1 - 7081 - 7082 + 7227 + 7228 1 @@ -3846,18 +3882,18 @@ 1 - 99 - 100 + 98 + 99 1 - 1040 - 1041 + 1061 + 1062 1 - 7081 - 7082 + 7227 + 7228 1 @@ -3874,7 +3910,7 @@ 1 2 - 8262 + 8428 @@ -3890,7 +3926,7 @@ 1 2 - 8262 + 8428 @@ -3900,15 +3936,15 @@ block_parameters_def - 7081 + 7227 id - 7081 + 7227 loc - 7081 + 7227 @@ -3922,7 +3958,7 @@ 1 2 - 7081 + 7227 @@ -3938,7 +3974,7 @@ 1 2 - 7081 + 7227 @@ -3996,15 +4032,15 @@ break_def - 210 + 214 id - 210 + 214 loc - 210 + 214 @@ -4018,7 +4054,7 @@ 1 2 - 210 + 214 @@ -4034,7 +4070,7 @@ 1 2 - 210 + 214 @@ -4044,15 +4080,15 @@ call_arguments - 212101 + 215041 call - 212101 + 215041 arguments - 212101 + 215041 @@ -4066,7 +4102,7 @@ 1 2 - 212101 + 215041 @@ -4082,7 +4118,7 @@ 1 2 - 212101 + 215041 @@ -4092,15 +4128,15 @@ call_block - 61428 + 62301 call - 61428 + 62301 block - 61428 + 62301 @@ -4114,7 +4150,7 @@ 1 2 - 61428 + 62301 @@ -4130,7 +4166,7 @@ 1 2 - 61428 + 62301 @@ -4140,19 +4176,19 @@ call_def - 300117 + 303820 id - 300117 + 303820 method - 300117 + 303820 loc - 300117 + 303820 @@ -4166,7 +4202,7 @@ 1 2 - 300117 + 303820 @@ -4182,7 +4218,7 @@ 1 2 - 300117 + 303820 @@ -4198,7 +4234,7 @@ 1 2 - 300117 + 303820 @@ -4214,7 +4250,7 @@ 1 2 - 300117 + 303820 @@ -4230,7 +4266,7 @@ 1 2 - 300117 + 303820 @@ -4246,7 +4282,7 @@ 1 2 - 300117 + 303820 @@ -4256,15 +4292,15 @@ call_receiver - 163154 + 166508 call - 163154 + 166508 receiver - 163154 + 166508 @@ -4278,7 +4314,7 @@ 1 2 - 163154 + 166508 @@ -4294,7 +4330,7 @@ 1 2 - 163154 + 166508 @@ -4304,19 +4340,19 @@ case_child - 1247 + 1267 case__ - 370 + 377 index - 23 + 22 child - 1247 + 1267 @@ -4335,26 +4371,26 @@ 2 3 - 99 + 102 3 4 - 155 + 156 4 5 - 58 + 60 5 7 - 28 + 29 7 - 24 + 23 20 @@ -4376,26 +4412,26 @@ 2 3 - 99 + 102 3 4 - 155 + 156 4 5 - 58 + 60 5 7 - 28 + 29 7 - 24 + 23 20 @@ -4412,7 +4448,7 @@ 1 2 - 9 + 8 2 @@ -4421,7 +4457,7 @@ 3 - 6 + 5 2 @@ -4436,17 +4472,17 @@ 30 - 49 + 50 2 - 106 - 262 + 109 + 266 2 - 360 - 371 + 367 + 378 2 @@ -4463,7 +4499,7 @@ 1 2 - 9 + 8 2 @@ -4472,7 +4508,7 @@ 3 - 6 + 5 2 @@ -4487,17 +4523,17 @@ 30 - 49 + 50 2 - 106 - 262 + 109 + 266 2 - 360 - 371 + 367 + 378 2 @@ -4514,7 +4550,7 @@ 1 2 - 1247 + 1267 @@ -4530,7 +4566,7 @@ 1 2 - 1247 + 1267 @@ -4540,15 +4576,15 @@ case_def - 370 + 377 id - 370 + 377 loc - 370 + 377 @@ -4562,7 +4598,7 @@ 1 2 - 370 + 377 @@ -4578,7 +4614,7 @@ 1 2 - 370 + 377 @@ -4588,15 +4624,15 @@ case_value - 358 + 365 case__ - 358 + 365 value - 358 + 365 @@ -4610,7 +4646,7 @@ 1 2 - 358 + 365 @@ -4626,7 +4662,7 @@ 1 2 - 358 + 365 @@ -4636,11 +4672,11 @@ chained_string_child - 1014 + 1031 chained_string - 262 + 268 index @@ -4648,7 +4684,7 @@ child - 1014 + 1031 @@ -4662,7 +4698,7 @@ 2 3 - 81 + 85 3 @@ -4672,12 +4708,12 @@ 4 5 - 42 + 43 5 6 - 37 + 38 6 @@ -4703,7 +4739,7 @@ 2 3 - 81 + 85 3 @@ -4713,12 +4749,12 @@ 4 5 - 42 + 43 5 6 - 37 + 38 6 @@ -4777,23 +4813,23 @@ 1 - 77 - 78 + 78 + 79 1 - 119 - 120 + 121 + 122 1 - 181 - 182 + 183 + 184 1 - 262 - 263 + 268 + 269 2 @@ -4843,23 +4879,23 @@ 1 - 77 - 78 + 78 + 79 1 - 119 - 120 + 121 + 122 1 - 181 - 182 + 183 + 184 1 - 262 - 263 + 268 + 269 2 @@ -4876,7 +4912,7 @@ 1 2 - 1014 + 1031 @@ -4892,7 +4928,7 @@ 1 2 - 1014 + 1031 @@ -4902,15 +4938,15 @@ chained_string_def - 262 + 268 id - 262 + 268 loc - 262 + 268 @@ -4924,7 +4960,7 @@ 1 2 - 262 + 268 @@ -4940,7 +4976,7 @@ 1 2 - 262 + 268 @@ -4950,11 +4986,11 @@ class_child - 39795 + 40498 class - 4572 + 4669 index @@ -4962,7 +4998,7 @@ child - 39795 + 40498 @@ -4976,57 +5012,52 @@ 1 2 - 1006 + 1013 2 3 - 711 + 726 3 4 - 455 + 465 4 5 - 377 + 399 5 6 - 288 + 296 6 - 7 - 254 + 8 + 430 - 7 - 9 - 335 + 8 + 11 + 402 - 9 - 13 - 390 + 11 + 16 + 373 - 13 - 21 - 359 + 16 + 33 + 355 - 21 - 81 - 343 - - - 83 + 33 306 - 54 + 210 @@ -5042,57 +5073,52 @@ 1 2 - 1006 + 1013 2 3 - 711 + 726 3 4 - 455 + 465 4 5 - 377 + 399 5 6 - 288 + 296 6 - 7 - 254 + 8 + 430 - 7 - 9 - 335 + 8 + 11 + 402 - 9 - 13 - 390 + 11 + 16 + 373 - 13 - 21 - 359 + 16 + 33 + 355 - 21 - 81 - 343 - - - 83 + 33 306 - 54 + 210 @@ -5113,10 +5139,15 @@ 2 3 - 33 + 25 3 + 4 + 8 + + + 4 5 24 @@ -5128,52 +5159,52 @@ 7 8 - 23 + 24 8 10 - 14 + 12 10 12 - 23 - - - 12 - 16 24 - 16 - 29 + 12 + 17 + 25 + + + 17 + 30 + 24 + + + 31 + 50 + 24 + + + 52 + 86 23 - 29 - 47 + 86 + 177 23 - 48 - 77 + 183 + 638 23 - 79 - 157 - 23 - - - 160 - 474 - 23 - - - 504 - 4573 - 17 + 698 + 4670 + 14 @@ -5194,10 +5225,15 @@ 2 3 - 33 + 25 3 + 4 + 8 + + + 4 5 24 @@ -5209,52 +5245,52 @@ 7 8 - 23 + 24 8 10 - 14 + 12 10 12 - 23 - - - 12 - 16 24 - 16 - 29 + 12 + 17 + 25 + + + 17 + 30 + 24 + + + 31 + 50 + 24 + + + 52 + 86 23 - 29 - 47 + 86 + 177 23 - 48 - 77 + 183 + 638 23 - 79 - 157 - 23 - - - 160 - 474 - 23 - - - 504 - 4573 - 17 + 698 + 4670 + 14 @@ -5270,7 +5306,7 @@ 1 2 - 39795 + 40498 @@ -5286,7 +5322,7 @@ 1 2 - 39795 + 40498 @@ -5296,19 +5332,19 @@ class_def - 5115 + 5194 id - 5115 + 5194 name - 5115 + 5194 loc - 5115 + 5194 @@ -5322,7 +5358,7 @@ 1 2 - 5115 + 5194 @@ -5338,7 +5374,7 @@ 1 2 - 5115 + 5194 @@ -5354,7 +5390,7 @@ 1 2 - 5115 + 5194 @@ -5370,7 +5406,7 @@ 1 2 - 5115 + 5194 @@ -5386,7 +5422,7 @@ 1 2 - 5115 + 5194 @@ -5402,7 +5438,7 @@ 1 2 - 5115 + 5194 @@ -5412,15 +5448,15 @@ class_superclass - 4039 + 4108 class - 4039 + 4108 superclass - 4039 + 4108 @@ -5434,7 +5470,7 @@ 1 2 - 4039 + 4108 @@ -5450,7 +5486,7 @@ 1 2 - 4039 + 4108 @@ -5460,27 +5496,27 @@ conditional_def - 1104 + 1120 id - 1104 + 1120 alternative - 1104 + 1120 condition - 1104 + 1120 consequence - 1104 + 1120 loc - 1104 + 1120 @@ -5494,7 +5530,7 @@ 1 2 - 1104 + 1120 @@ -5510,7 +5546,7 @@ 1 2 - 1104 + 1120 @@ -5526,7 +5562,7 @@ 1 2 - 1104 + 1120 @@ -5542,7 +5578,7 @@ 1 2 - 1104 + 1120 @@ -5558,7 +5594,7 @@ 1 2 - 1104 + 1120 @@ -5574,7 +5610,7 @@ 1 2 - 1104 + 1120 @@ -5590,7 +5626,7 @@ 1 2 - 1104 + 1120 @@ -5606,7 +5642,7 @@ 1 2 - 1104 + 1120 @@ -5622,7 +5658,7 @@ 1 2 - 1104 + 1120 @@ -5638,7 +5674,7 @@ 1 2 - 1104 + 1120 @@ -5654,7 +5690,7 @@ 1 2 - 1104 + 1120 @@ -5670,7 +5706,7 @@ 1 2 - 1104 + 1120 @@ -5686,7 +5722,7 @@ 1 2 - 1104 + 1120 @@ -5702,7 +5738,7 @@ 1 2 - 1104 + 1120 @@ -5718,7 +5754,7 @@ 1 2 - 1104 + 1120 @@ -5734,7 +5770,7 @@ 1 2 - 1104 + 1120 @@ -5750,7 +5786,7 @@ 1 2 - 1104 + 1120 @@ -5766,7 +5802,7 @@ 1 2 - 1104 + 1120 @@ -5782,7 +5818,7 @@ 1 2 - 1104 + 1120 @@ -5798,7 +5834,7 @@ 1 2 - 1104 + 1120 @@ -5808,15 +5844,15 @@ containerparent - 7635 + 7808 parent - 1459 + 1489 child - 7635 + 7808 @@ -5830,37 +5866,42 @@ 1 2 - 530 + 538 2 3 - 303 + 306 3 4 - 115 + 119 4 5 - 157 + 160 5 - 7 - 129 + 6 + 102 - 7 - 12 - 132 + 6 + 10 + 115 - 12 - 290 - 90 + 10 + 30 + 112 + + + 30 + 295 + 34 @@ -5876,7 +5917,7 @@ 1 2 - 7635 + 7808 @@ -5886,11 +5927,11 @@ delimited_symbol_child - 523 + 529 delimited_symbol - 379 + 384 index @@ -5898,7 +5939,7 @@ child - 523 + 529 @@ -5912,12 +5953,12 @@ 1 2 - 286 + 290 2 3 - 71 + 72 3 @@ -5938,12 +5979,12 @@ 1 2 - 286 + 290 2 3 - 71 + 72 3 @@ -5992,13 +6033,13 @@ 1 - 93 - 94 + 94 + 95 1 - 379 - 380 + 384 + 385 1 @@ -6043,13 +6084,13 @@ 1 - 93 - 94 + 94 + 95 1 - 379 - 380 + 384 + 385 1 @@ -6066,7 +6107,7 @@ 1 2 - 523 + 529 @@ -6082,7 +6123,7 @@ 1 2 - 523 + 529 @@ -6092,15 +6133,15 @@ delimited_symbol_def - 379 + 384 id - 379 + 384 loc - 379 + 384 @@ -6114,7 +6155,7 @@ 1 2 - 379 + 384 @@ -6130,7 +6171,7 @@ 1 2 - 379 + 384 @@ -6304,11 +6345,11 @@ destructured_parameter_child - 125 + 127 destructured_parameter - 61 + 62 index @@ -6316,7 +6357,7 @@ child - 125 + 127 @@ -6335,7 +6376,7 @@ 2 3 - 53 + 54 3 @@ -6361,7 +6402,7 @@ 2 3 - 53 + 54 3 @@ -6390,13 +6431,13 @@ 1 - 58 - 59 + 59 + 60 1 - 61 - 62 + 62 + 63 1 @@ -6421,13 +6462,13 @@ 1 - 58 - 59 + 59 + 60 1 - 61 - 62 + 62 + 63 1 @@ -6444,7 +6485,7 @@ 1 2 - 125 + 127 @@ -6460,7 +6501,7 @@ 1 2 - 125 + 127 @@ -6470,15 +6511,15 @@ destructured_parameter_def - 61 + 62 id - 61 + 62 loc - 61 + 62 @@ -6492,7 +6533,7 @@ 1 2 - 61 + 62 @@ -6501,6 +6542,410 @@ loc id + + + 12 + + + 1 + 2 + 62 + + + + + + + + + diagnostics + 64 + + + id + 64 + + + severity + 3 + + + error_tag + 3 + + + error_message + 13 + + + full_error_message + 61 + + + location + 64 + + + + + id + severity + + + 12 + + + 1 + 2 + 64 + + + + + + + id + error_tag + + + 12 + + + 1 + 2 + 64 + + + + + + + id + error_message + + + 12 + + + 1 + 2 + 64 + + + + + + + id + full_error_message + + + 12 + + + 1 + 2 + 64 + + + + + + + id + location + + + 12 + + + 1 + 2 + 64 + + + + + + + severity + id + + + 12 + + + 19 + 20 + 3 + + + + + + + severity + error_tag + + + 12 + + + 1 + 2 + 3 + + + + + + + severity + error_message + + + 12 + + + 4 + 5 + 3 + + + + + + + severity + full_error_message + + + 12 + + + 18 + 19 + 3 + + + + + + + severity + location + + + 12 + + + 19 + 20 + 3 + + + + + + + error_tag + id + + + 12 + + + 19 + 20 + 3 + + + + + + + error_tag + severity + + + 12 + + + 1 + 2 + 3 + + + + + + + error_tag + error_message + + + 12 + + + 4 + 5 + 3 + + + + + + + error_tag + full_error_message + + + 12 + + + 18 + 19 + 3 + + + + + + + error_tag + location + + + 12 + + + 19 + 20 + 3 + + + + + + + error_message + id + + + 12 + + + 1 + 2 + 10 + + + 16 + 17 + 3 + + + + + + + error_message + severity + + + 12 + + + 1 + 2 + 13 + + + + + + + error_message + error_tag + + + 12 + + + 1 + 2 + 13 + + + + + + + error_message + full_error_message + + + 12 + + + 1 + 2 + 10 + + + 15 + 16 + 3 + + + + + + + error_message + location + + + 12 + + + 1 + 2 + 10 + + + 16 + 17 + 3 + + + + + + + full_error_message + id + + + 12 + + + 1 + 2 + 57 + + + 2 + 3 + 3 + + + + + + + full_error_message + severity 12 @@ -6514,23 +6959,156 @@ + + full_error_message + error_tag + + + 12 + + + 1 + 2 + 61 + + + + + + + full_error_message + error_message + + + 12 + + + 1 + 2 + 61 + + + + + + + full_error_message + location + + + 12 + + + 1 + 2 + 57 + + + 2 + 3 + 3 + + + + + + + location + id + + + 12 + + + 1 + 2 + 64 + + + + + + + location + severity + + + 12 + + + 1 + 2 + 64 + + + + + + + location + error_tag + + + 12 + + + 1 + 2 + 64 + + + + + + + location + error_message + + + 12 + + + 1 + 2 + 64 + + + + + + + location + full_error_message + + + 12 + + + 1 + 2 + 64 + + + + + do_block_child - 119505 + 121320 do_block - 41136 + 41642 index - 199 + 245 child - 119505 + 121320 @@ -6544,32 +7122,32 @@ 1 2 - 13092 + 13351 2 3 - 11630 + 11657 3 4 - 6584 + 6680 4 5 - 3571 + 3602 5 7 - 3306 + 3347 7 - 58 - 2950 + 73 + 3002 @@ -6585,32 +7163,32 @@ 1 2 - 13092 + 13351 2 3 - 11630 + 11657 3 4 - 6584 + 6680 4 5 - 3571 + 3602 5 7 - 3306 + 3347 7 - 58 - 2950 + 73 + 3002 @@ -6626,58 +7204,53 @@ 1 2 - 34 + 47 2 3 - 20 + 37 3 - 4 - 6 + 5 + 20 5 7 - 17 + 20 - 10 - 14 - 17 + 8 + 16 + 20 - 15 - 27 - 17 + 17 + 33 + 20 - 29 - 46 - 17 + 35 + 71 + 20 - 54 - 118 - 17 + 84 + 245 + 20 - 139 - 358 - 17 + 294 + 1246 + 20 - 459 - 1793 + 1863 + 12218 17 - - 2815 - 11783 - 13 - @@ -6692,58 +7265,53 @@ 1 2 - 34 + 47 2 3 - 20 + 37 3 - 4 - 6 + 5 + 20 5 7 - 17 + 20 - 10 - 14 - 17 + 8 + 16 + 20 - 15 - 27 - 17 + 17 + 33 + 20 - 29 - 46 - 17 + 35 + 71 + 20 - 54 - 118 - 17 + 84 + 245 + 20 - 139 - 358 - 17 + 294 + 1246 + 20 - 459 - 1793 + 1863 + 12218 17 - - 2815 - 11783 - 13 - @@ -6758,7 +7326,7 @@ 1 2 - 119505 + 121320 @@ -6774,7 +7342,7 @@ 1 2 - 119505 + 121320 @@ -6784,15 +7352,15 @@ do_block_def - 41153 + 41659 id - 41153 + 41659 loc - 41153 + 41659 @@ -6806,7 +7374,7 @@ 1 2 - 41153 + 41659 @@ -6822,7 +7390,7 @@ 1 2 - 41153 + 41659 @@ -6832,15 +7400,15 @@ do_block_parameters - 4451 + 4565 do_block - 4451 + 4565 parameters - 4451 + 4565 @@ -6854,7 +7422,7 @@ 1 2 - 4451 + 4565 @@ -6870,7 +7438,7 @@ 1 2 - 4451 + 4565 @@ -6880,11 +7448,11 @@ do_child - 267 + 268 do - 113 + 114 index @@ -6892,7 +7460,7 @@ child - 267 + 268 @@ -6906,7 +7474,7 @@ 1 2 - 32 + 34 2 @@ -6942,7 +7510,7 @@ 1 2 - 32 + 34 2 @@ -7011,8 +7579,8 @@ 1 - 110 - 111 + 112 + 113 1 @@ -7062,8 +7630,8 @@ 1 - 110 - 111 + 112 + 113 1 @@ -7080,7 +7648,7 @@ 1 2 - 267 + 268 @@ -7096,7 +7664,7 @@ 1 2 - 267 + 268 @@ -7106,15 +7674,15 @@ do_def - 116 + 117 id - 116 + 117 loc - 116 + 117 @@ -7128,7 +7696,7 @@ 1 2 - 116 + 117 @@ -7144,7 +7712,7 @@ 1 2 - 116 + 117 @@ -7154,11 +7722,11 @@ element_reference_child - 25109 + 25626 element_reference - 25062 + 25580 index @@ -7166,7 +7734,7 @@ child - 25109 + 25626 @@ -7180,7 +7748,7 @@ 1 2 - 25016 + 25534 2 @@ -7201,7 +7769,7 @@ 1 2 - 25016 + 25534 2 @@ -7225,8 +7793,8 @@ 1 - 24365 - 24366 + 24988 + 24989 1 @@ -7246,8 +7814,8 @@ 1 - 24365 - 24366 + 24988 + 24989 1 @@ -7264,7 +7832,7 @@ 1 2 - 25109 + 25626 @@ -7280,7 +7848,7 @@ 1 2 - 25109 + 25626 @@ -7290,19 +7858,19 @@ element_reference_def - 25064 + 25582 id - 25064 + 25582 object - 25064 + 25582 loc - 25064 + 25582 @@ -7316,7 +7884,7 @@ 1 2 - 25064 + 25582 @@ -7332,7 +7900,7 @@ 1 2 - 25064 + 25582 @@ -7348,7 +7916,7 @@ 1 2 - 25064 + 25582 @@ -7364,7 +7932,7 @@ 1 2 - 25064 + 25582 @@ -7380,7 +7948,7 @@ 1 2 - 25064 + 25582 @@ -7396,7 +7964,7 @@ 1 2 - 25064 + 25582 @@ -7406,19 +7974,19 @@ else_child - 2648 + 2696 else - 2070 + 2119 index - 12 + 11 child - 2648 + 2696 @@ -7432,17 +8000,17 @@ 1 2 - 1745 + 1786 2 3 - 198 + 207 3 - 13 - 127 + 12 + 126 @@ -7458,17 +8026,17 @@ 1 2 - 1745 + 1786 2 3 - 198 + 207 3 - 13 - 127 + 12 + 126 @@ -7486,11 +8054,6 @@ 2 1 - - 2 - 3 - 1 - 3 4 @@ -7507,8 +8070,8 @@ 1 - 10 - 11 + 8 + 9 1 @@ -7517,28 +8080,28 @@ 1 - 28 - 29 + 27 + 28 1 - 56 - 57 + 53 + 54 1 - 127 - 128 + 126 + 127 1 - 325 - 326 + 333 + 334 1 - 2070 - 2071 + 2119 + 2120 1 @@ -7557,11 +8120,6 @@ 2 1 - - 2 - 3 - 1 - 3 4 @@ -7578,8 +8136,8 @@ 1 - 10 - 11 + 8 + 9 1 @@ -7588,28 +8146,28 @@ 1 - 28 - 29 + 27 + 28 1 - 56 - 57 + 53 + 54 1 - 127 - 128 + 126 + 127 1 - 325 - 326 + 333 + 334 1 - 2070 - 2071 + 2119 + 2120 1 @@ -7626,7 +8184,7 @@ 1 2 - 2648 + 2696 @@ -7642,7 +8200,7 @@ 1 2 - 2648 + 2696 @@ -7652,15 +8210,15 @@ else_def - 2073 + 2122 id - 2073 + 2122 loc - 2073 + 2122 @@ -7674,7 +8232,7 @@ 1 2 - 2073 + 2122 @@ -7690,7 +8248,7 @@ 1 2 - 2073 + 2122 @@ -7700,15 +8258,15 @@ elsif_alternative - 259 + 271 elsif - 259 + 271 alternative - 259 + 271 @@ -7722,7 +8280,7 @@ 1 2 - 259 + 271 @@ -7738,7 +8296,7 @@ 1 2 - 259 + 271 @@ -7748,15 +8306,15 @@ elsif_consequence - 473 + 491 elsif - 473 + 491 consequence - 473 + 491 @@ -7770,7 +8328,7 @@ 1 2 - 473 + 491 @@ -7786,7 +8344,7 @@ 1 2 - 473 + 491 @@ -7796,19 +8354,19 @@ elsif_def - 474 + 491 id - 474 + 491 condition - 474 + 491 loc - 474 + 491 @@ -7822,7 +8380,7 @@ 1 2 - 474 + 491 @@ -7838,7 +8396,7 @@ 1 2 - 474 + 491 @@ -7854,7 +8412,7 @@ 1 2 - 474 + 491 @@ -7870,7 +8428,7 @@ 1 2 - 474 + 491 @@ -7886,7 +8444,7 @@ 1 2 - 474 + 491 @@ -7902,7 +8460,7 @@ 1 2 - 474 + 491 @@ -8046,11 +8604,11 @@ ensure_child - 1549 + 1517 ensure - 1152 + 1125 index @@ -8058,7 +8616,7 @@ child - 1549 + 1517 @@ -8072,22 +8630,22 @@ 1 2 - 901 + 878 2 3 - 161 + 156 3 - 9 - 88 + 5 + 85 - 16 + 6 17 - 2 + 6 @@ -8103,22 +8661,22 @@ 1 2 - 901 + 878 2 3 - 161 + 156 3 - 9 - 88 + 5 + 85 - 16 + 6 17 - 2 + 6 @@ -8144,31 +8702,26 @@ 6 7 + 2 + + + 16 + 17 1 - 7 - 8 + 91 + 92 1 - 17 - 18 + 247 + 248 1 - 90 - 91 - 1 - - - 251 - 252 - 1 - - - 1152 - 1153 + 1125 + 1126 1 @@ -8195,31 +8748,26 @@ 6 7 + 2 + + + 16 + 17 1 - 7 - 8 + 91 + 92 1 - 17 - 18 + 247 + 248 1 - 90 - 91 - 1 - - - 251 - 252 - 1 - - - 1152 - 1153 + 1125 + 1126 1 @@ -8236,7 +8784,7 @@ 1 2 - 1549 + 1517 @@ -8252,7 +8800,7 @@ 1 2 - 1549 + 1517 @@ -8262,15 +8810,15 @@ ensure_def - 1152 + 1125 id - 1152 + 1125 loc - 1152 + 1125 @@ -8284,7 +8832,7 @@ 1 2 - 1152 + 1125 @@ -8300,7 +8848,7 @@ 1 2 - 1152 + 1125 @@ -8310,19 +8858,19 @@ exception_variable_def - 298 + 309 id - 298 + 309 child - 298 + 309 loc - 298 + 309 @@ -8336,7 +8884,7 @@ 1 2 - 298 + 309 @@ -8352,7 +8900,7 @@ 1 2 - 298 + 309 @@ -8368,7 +8916,7 @@ 1 2 - 298 + 309 @@ -8384,7 +8932,7 @@ 1 2 - 298 + 309 @@ -8400,7 +8948,7 @@ 1 2 - 298 + 309 @@ -8416,7 +8964,7 @@ 1 2 - 298 + 309 @@ -8426,11 +8974,11 @@ exceptions_child - 473 + 496 exceptions - 416 + 429 index @@ -8438,7 +8986,7 @@ child - 473 + 496 @@ -8452,17 +9000,17 @@ 1 2 - 376 + 386 2 - 4 - 38 + 3 + 30 - 4 + 3 9 - 2 + 12 @@ -8478,17 +9026,17 @@ 1 2 - 376 + 386 2 - 4 - 38 + 3 + 30 - 4 + 3 9 - 2 + 12 @@ -8502,28 +9050,28 @@ 12 - 1 - 2 + 2 + 3 4 - 2 - 3 + 3 + 4 1 - 10 - 11 + 12 + 13 1 - 39 - 40 + 42 + 43 1 - 405 - 406 + 420 + 421 1 @@ -8538,28 +9086,28 @@ 12 - 1 - 2 + 2 + 3 4 - 2 - 3 + 3 + 4 1 - 10 - 11 + 12 + 13 1 - 39 - 40 + 42 + 43 1 - 405 - 406 + 420 + 421 1 @@ -8576,7 +9124,7 @@ 1 2 - 473 + 496 @@ -8592,7 +9140,7 @@ 1 2 - 473 + 496 @@ -8602,15 +9150,15 @@ exceptions_def - 416 + 429 id - 416 + 429 loc - 416 + 429 @@ -8624,7 +9172,7 @@ 1 2 - 416 + 429 @@ -8640,7 +9188,7 @@ 1 2 - 416 + 429 @@ -8650,19 +9198,19 @@ files - 6179 + 6322 id - 6179 + 6322 name - 6179 + 6322 simple - 4811 + 4840 ext @@ -8684,7 +9232,7 @@ 1 2 - 6179 + 6322 @@ -8700,7 +9248,7 @@ 1 2 - 6179 + 6322 @@ -8716,7 +9264,7 @@ 1 2 - 6179 + 6322 @@ -8732,7 +9280,7 @@ 1 2 - 6179 + 6322 @@ -8748,7 +9296,7 @@ 1 2 - 6179 + 6322 @@ -8764,7 +9312,7 @@ 1 2 - 6179 + 6322 @@ -8780,7 +9328,7 @@ 1 2 - 6179 + 6322 @@ -8796,7 +9344,7 @@ 1 2 - 6179 + 6322 @@ -8812,17 +9360,17 @@ 1 2 - 4252 + 4212 2 3 - 380 + 429 3 - 44 - 178 + 45 + 197 @@ -8838,17 +9386,17 @@ 1 2 - 4252 + 4212 2 3 - 380 + 429 3 - 44 - 178 + 45 + 197 @@ -8864,7 +9412,7 @@ 1 2 - 4811 + 4840 @@ -8880,7 +9428,7 @@ 1 2 - 4811 + 4840 @@ -8894,13 +9442,13 @@ 12 - 415 - 416 + 429 + 430 3 - 1355 - 1356 + 1426 + 1427 3 @@ -8915,13 +9463,13 @@ 12 - 415 - 416 + 429 + 430 3 - 1355 - 1356 + 1426 + 1427 3 @@ -8936,13 +9484,13 @@ 12 - 214 - 215 + 220 + 221 3 - 1164 - 1165 + 1200 + 1201 3 @@ -8973,8 +9521,8 @@ 12 - 1770 - 1771 + 1855 + 1856 3 @@ -8989,8 +9537,8 @@ 12 - 1770 - 1771 + 1855 + 1856 3 @@ -9005,8 +9553,8 @@ 12 - 1378 - 1379 + 1420 + 1421 3 @@ -9033,19 +9581,19 @@ folders - 1459 + 1489 id - 1459 + 1489 name - 1459 + 1489 simple - 624 + 630 @@ -9059,7 +9607,7 @@ 1 2 - 1459 + 1489 @@ -9075,7 +9623,7 @@ 1 2 - 1459 + 1489 @@ -9091,7 +9639,7 @@ 1 2 - 1459 + 1489 @@ -9107,7 +9655,7 @@ 1 2 - 1459 + 1489 @@ -9123,27 +9671,27 @@ 1 2 - 338 + 337 2 3 - 150 + 153 3 4 - 48 + 51 4 7 - 48 + 54 7 - 53 - 38 + 54 + 34 @@ -9159,27 +9707,27 @@ 1 2 - 338 + 337 2 3 - 150 + 153 3 4 - 48 + 51 4 7 - 48 + 54 7 - 53 - 38 + 54 + 34 @@ -9537,19 +10085,19 @@ hash_child - 14574 + 14706 hash - 6601 + 6654 index - 114 + 113 child - 14574 + 14706 @@ -9563,27 +10111,27 @@ 1 2 - 3362 + 3375 2 3 - 1728 + 1747 3 4 - 691 + 688 4 6 - 501 + 516 6 112 - 317 + 325 @@ -9599,27 +10147,27 @@ 1 2 - 3362 + 3375 2 3 - 1728 + 1747 3 4 - 691 + 688 4 6 - 501 + 516 6 112 - 317 + 325 @@ -9635,7 +10183,7 @@ 1 2 - 43 + 42 2 @@ -9644,22 +10192,22 @@ 3 - 11 + 10 4 + + 10 + 11 + 9 + 11 - 12 + 23 9 - 12 - 24 - 9 - - - 24 - 33 + 23 + 32 8 @@ -9668,13 +10216,13 @@ 9 - 81 - 3150 + 82 + 3204 9 - 6418 - 6419 + 6500 + 6501 1 @@ -9691,7 +10239,7 @@ 1 2 - 43 + 42 2 @@ -9700,22 +10248,22 @@ 3 - 11 + 10 4 + + 10 + 11 + 9 + 11 - 12 + 23 9 - 12 - 24 - 9 - - - 24 - 33 + 23 + 32 8 @@ -9724,13 +10272,13 @@ 9 - 81 - 3150 + 82 + 3204 9 - 6418 - 6419 + 6500 + 6501 1 @@ -9747,7 +10295,7 @@ 1 2 - 14574 + 14706 @@ -9763,7 +10311,7 @@ 1 2 - 14574 + 14706 @@ -9773,15 +10321,15 @@ hash_def - 8043 + 8122 id - 8043 + 8122 loc - 8043 + 8122 @@ -9795,7 +10343,7 @@ 1 2 - 8043 + 8122 @@ -9811,7 +10359,7 @@ 1 2 - 8043 + 8122 @@ -9821,19 +10369,19 @@ hash_splat_argument_def - 369 + 398 id - 369 + 398 child - 369 + 398 loc - 369 + 398 @@ -9847,7 +10395,7 @@ 1 2 - 369 + 398 @@ -9863,7 +10411,7 @@ 1 2 - 369 + 398 @@ -9879,7 +10427,7 @@ 1 2 - 369 + 398 @@ -9895,7 +10443,7 @@ 1 2 - 369 + 398 @@ -9911,7 +10459,7 @@ 1 2 - 369 + 398 @@ -9927,7 +10475,7 @@ 1 2 - 369 + 398 @@ -9937,15 +10485,15 @@ hash_splat_parameter_def - 402 + 413 id - 402 + 413 loc - 402 + 413 @@ -9959,7 +10507,7 @@ 1 2 - 402 + 413 @@ -9975,7 +10523,7 @@ 1 2 - 402 + 413 @@ -9985,15 +10533,15 @@ hash_splat_parameter_name - 338 + 350 hash_splat_parameter - 338 + 350 name - 338 + 350 @@ -10007,7 +10555,7 @@ 1 2 - 338 + 350 @@ -10023,7 +10571,7 @@ 1 2 - 338 + 350 @@ -10033,19 +10581,19 @@ heredoc_body_child - 7176 + 7402 heredoc_body - 1567 + 1610 index - 72 + 73 child - 7176 + 7402 @@ -10059,12 +10607,12 @@ 2 3 - 885 + 903 4 5 - 183 + 187 5 @@ -10074,22 +10622,22 @@ 6 7 - 235 + 247 7 9 - 92 + 94 10 15 - 120 + 124 16 - 71 - 49 + 73 + 51 @@ -10105,12 +10653,12 @@ 2 3 - 885 + 903 4 5 - 183 + 187 5 @@ -10120,22 +10668,22 @@ 6 7 - 235 + 247 7 9 - 92 + 94 10 15 - 120 + 124 16 - 71 - 49 + 73 + 51 @@ -10151,7 +10699,7 @@ 1 2 - 20 + 22 2 @@ -10185,22 +10733,22 @@ 24 - 49 + 51 6 - 72 - 166 + 77 + 173 6 - 251 - 664 + 260 + 691 6 - 1524 - 1525 + 1573 + 1574 2 @@ -10217,7 +10765,7 @@ 1 2 - 20 + 22 2 @@ -10251,22 +10799,22 @@ 24 - 49 + 51 6 - 72 - 166 + 77 + 173 6 - 251 - 664 + 260 + 691 6 - 1524 - 1525 + 1573 + 1574 2 @@ -10283,7 +10831,7 @@ 1 2 - 7176 + 7402 @@ -10299,7 +10847,7 @@ 1 2 - 7176 + 7402 @@ -10309,15 +10857,15 @@ heredoc_body_def - 1567 + 1610 id - 1567 + 1610 loc - 1567 + 1610 @@ -10331,7 +10879,7 @@ 1 2 - 1567 + 1610 @@ -10347,7 +10895,7 @@ 1 2 - 1567 + 1610 @@ -10357,15 +10905,15 @@ if_alternative - 1914 + 1962 if - 1914 + 1962 alternative - 1914 + 1962 @@ -10379,7 +10927,7 @@ 1 2 - 1914 + 1962 @@ -10395,7 +10943,7 @@ 1 2 - 1914 + 1962 @@ -10405,15 +10953,15 @@ if_consequence - 5593 + 5694 if - 5593 + 5694 consequence - 5593 + 5694 @@ -10427,7 +10975,7 @@ 1 2 - 5593 + 5694 @@ -10443,7 +10991,7 @@ 1 2 - 5593 + 5694 @@ -10453,19 +11001,19 @@ if_def - 5609 + 5713 id - 5609 + 5713 condition - 5609 + 5713 loc - 5609 + 5713 @@ -10479,7 +11027,7 @@ 1 2 - 5609 + 5713 @@ -10495,7 +11043,7 @@ 1 2 - 5609 + 5713 @@ -10511,7 +11059,7 @@ 1 2 - 5609 + 5713 @@ -10527,7 +11075,7 @@ 1 2 - 5609 + 5713 @@ -10543,7 +11091,7 @@ 1 2 - 5609 + 5713 @@ -10559,7 +11107,7 @@ 1 2 - 5609 + 5713 @@ -10569,23 +11117,23 @@ if_modifier_def - 4182 + 4276 id - 4182 + 4276 body - 4182 + 4276 condition - 4182 + 4276 loc - 4182 + 4276 @@ -10599,7 +11147,7 @@ 1 2 - 4182 + 4276 @@ -10615,7 +11163,7 @@ 1 2 - 4182 + 4276 @@ -10631,7 +11179,7 @@ 1 2 - 4182 + 4276 @@ -10647,7 +11195,7 @@ 1 2 - 4182 + 4276 @@ -10663,7 +11211,7 @@ 1 2 - 4182 + 4276 @@ -10679,7 +11227,7 @@ 1 2 - 4182 + 4276 @@ -10695,7 +11243,7 @@ 1 2 - 4182 + 4276 @@ -10711,7 +11259,7 @@ 1 2 - 4182 + 4276 @@ -10727,7 +11275,7 @@ 1 2 - 4182 + 4276 @@ -10743,7 +11291,7 @@ 1 2 - 4182 + 4276 @@ -10759,7 +11307,7 @@ 1 2 - 4182 + 4276 @@ -10775,7 +11323,7 @@ 1 2 - 4182 + 4276 @@ -10901,11 +11449,11 @@ interpolation_child - 11532 + 11773 interpolation - 11532 + 11773 index @@ -10913,7 +11461,7 @@ child - 11532 + 11773 @@ -10927,7 +11475,7 @@ 1 2 - 11532 + 11773 @@ -10943,7 +11491,7 @@ 1 2 - 11532 + 11773 @@ -10957,8 +11505,8 @@ 12 - 11211 - 11212 + 11501 + 11502 1 @@ -10973,8 +11521,8 @@ 12 - 11211 - 11212 + 11501 + 11502 1 @@ -10991,7 +11539,7 @@ 1 2 - 11532 + 11773 @@ -11007,7 +11555,7 @@ 1 2 - 11532 + 11773 @@ -11017,15 +11565,15 @@ interpolation_def - 11532 + 11773 id - 11532 + 11773 loc - 11532 + 11773 @@ -11039,7 +11587,7 @@ 1 2 - 11532 + 11773 @@ -11055,7 +11603,7 @@ 1 2 - 11532 + 11773 @@ -11065,19 +11613,19 @@ keyword_parameter_def - 1006 + 1099 id - 1006 + 1099 name - 1006 + 1099 loc - 1006 + 1099 @@ -11091,7 +11639,7 @@ 1 2 - 1006 + 1099 @@ -11107,7 +11655,7 @@ 1 2 - 1006 + 1099 @@ -11123,7 +11671,7 @@ 1 2 - 1006 + 1099 @@ -11139,7 +11687,7 @@ 1 2 - 1006 + 1099 @@ -11155,7 +11703,7 @@ 1 2 - 1006 + 1099 @@ -11171,7 +11719,7 @@ 1 2 - 1006 + 1099 @@ -11181,15 +11729,15 @@ keyword_parameter_value - 745 + 812 keyword_parameter - 745 + 812 value - 745 + 812 @@ -11203,7 +11751,7 @@ 1 2 - 745 + 812 @@ -11219,7 +11767,7 @@ 1 2 - 745 + 812 @@ -11229,19 +11777,19 @@ lambda_def - 636 + 660 id - 636 + 660 body - 636 + 660 loc - 636 + 660 @@ -11255,7 +11803,7 @@ 1 2 - 636 + 660 @@ -11271,7 +11819,7 @@ 1 2 - 636 + 660 @@ -11287,7 +11835,7 @@ 1 2 - 636 + 660 @@ -11303,7 +11851,7 @@ 1 2 - 636 + 660 @@ -11319,7 +11867,7 @@ 1 2 - 636 + 660 @@ -11335,7 +11883,7 @@ 1 2 - 636 + 660 @@ -11345,15 +11893,15 @@ lambda_parameters - 184 + 190 lambda - 184 + 190 parameters - 184 + 190 @@ -11367,7 +11915,7 @@ 1 2 - 184 + 190 @@ -11383,7 +11931,7 @@ 1 2 - 184 + 190 @@ -11393,11 +11941,11 @@ lambda_parameters_child - 239 + 243 lambda_parameters - 181 + 185 index @@ -11405,7 +11953,7 @@ child - 239 + 243 @@ -11419,7 +11967,7 @@ 1 2 - 143 + 147 2 @@ -11445,7 +11993,7 @@ 1 2 - 143 + 147 2 @@ -11484,8 +12032,8 @@ 1 - 181 - 182 + 185 + 186 1 @@ -11515,8 +12063,8 @@ 1 - 181 - 182 + 185 + 186 1 @@ -11533,7 +12081,7 @@ 1 2 - 239 + 243 @@ -11549,7 +12097,7 @@ 1 2 - 239 + 243 @@ -11559,15 +12107,15 @@ lambda_parameters_def - 184 + 190 id - 184 + 190 loc - 184 + 190 @@ -11581,7 +12129,7 @@ 1 2 - 184 + 190 @@ -11597,7 +12145,7 @@ 1 2 - 184 + 190 @@ -11607,11 +12155,11 @@ left_assignment_list_child - 1694 + 1721 left_assignment_list - 762 + 773 index @@ -11619,7 +12167,7 @@ child - 1694 + 1721 @@ -11638,12 +12186,12 @@ 2 3 - 626 + 632 3 4 - 113 + 118 4 @@ -11669,12 +12217,12 @@ 2 3 - 626 + 632 3 4 - 113 + 118 4 @@ -11713,18 +12261,18 @@ 1 - 134 - 135 + 139 + 140 1 - 760 - 761 + 771 + 772 1 - 762 - 763 + 773 + 774 1 @@ -11759,18 +12307,18 @@ 1 - 134 - 135 + 139 + 140 1 - 760 - 761 + 771 + 772 1 - 762 - 763 + 773 + 774 1 @@ -11787,7 +12335,7 @@ 1 2 - 1694 + 1721 @@ -11803,7 +12351,7 @@ 1 2 - 1694 + 1721 @@ -11813,15 +12361,15 @@ left_assignment_list_def - 762 + 773 id - 762 + 773 loc - 762 + 773 @@ -11835,7 +12383,7 @@ 1 2 - 762 + 773 @@ -11851,7 +12399,7 @@ 1 2 - 762 + 773 @@ -11861,31 +12409,31 @@ locations_default - 2557616 + 2604972 id - 2557616 + 2604972 file - 6179 + 6322 start_line - 4556 + 4526 start_column - 1085 + 1060 end_line - 4556 + 4526 end_column - 1096 + 1070 @@ -11899,7 +12447,7 @@ 1 2 - 2557616 + 2604972 @@ -11915,7 +12463,7 @@ 1 2 - 2557616 + 2604972 @@ -11931,7 +12479,7 @@ 1 2 - 2557616 + 2604972 @@ -11947,7 +12495,7 @@ 1 2 - 2557616 + 2604972 @@ -11963,7 +12511,7 @@ 1 2 - 2557616 + 2604972 @@ -11979,72 +12527,72 @@ 1 28 - 502 + 487 28 - 43 - 495 + 42 + 484 - 43 - 66 - 481 + 42 + 63 + 477 - 66 - 88 - 474 + 63 + 83 + 477 - 88 - 108 - 467 + 83 + 100 + 477 - 108 - 144 - 464 + 100 + 137 + 480 - 144 - 188 - 464 + 137 + 181 + 497 - 188 - 240 - 464 + 181 + 228 + 477 - 241 - 319 - 464 + 228 + 310 + 484 - 319 - 421 - 464 + 311 + 416 + 480 - 423 - 619 - 464 + 416 + 593 + 480 - 621 - 1054 - 464 + 593 + 1000 + 477 - 1057 - 5499 - 464 + 1002 + 4862 + 477 - 5618 - 10809 - 41 + 4991 + 11002 + 64 @@ -12060,165 +12608,165 @@ 1 5 - 373 - - - 5 - 6 - 467 - - - 6 - 8 - 415 - - - 8 - 10 - 492 - - - 10 - 13 - 537 - - - 13 - 17 - 530 - - - 17 - 22 - 530 - - - 22 - 29 - 506 - - - 29 - 39 - 534 - - - 39 - 52 - 471 - - - 52 - 76 - 464 - - - 76 - 150 - 471 - - - 150 - 1116 - 384 - - - - - - - file - start_column - - - 12 - - - 1 - 16 - 506 - - - 16 - 22 - 464 - - - 22 - 30 - 492 - - - 30 - 38 - 495 - - - 38 - 44 - 495 - - - 44 - 52 - 485 - - - 52 - 60 - 502 - - - 60 - 68 - 509 - - - 68 - 75 - 513 - - - 75 - 85 - 474 - - - 85 - 96 - 474 - - - 96 - 117 - 478 - - - 117 - 241 - 286 - - - - - - - file - end_line - - - 12 - - - 1 - 5 - 373 + 368 5 6 460 + + 6 + 8 + 412 + + + 8 + 10 + 507 + + + 10 + 13 + 572 + + + 13 + 17 + 555 + + + 17 + 22 + 559 + + + 22 + 29 + 524 + + + 29 + 39 + 538 + + + 39 + 52 + 477 + + + 52 + 76 + 480 + + + 76 + 150 + 477 + + + 150 + 1135 + 388 + + + + + + + file + start_column + + + 12 + + + 1 + 16 + 487 + + + 16 + 22 + 528 + + + 22 + 30 + 501 + + + 30 + 38 + 524 + + + 38 + 44 + 490 + + + 44 + 51 + 480 + + + 51 + 59 + 494 + + + 59 + 67 + 490 + + + 67 + 74 + 497 + + + 74 + 84 + 507 + + + 84 + 95 + 490 + + + 95 + 114 + 477 + + + 114 + 241 + 351 + + + + + + + file + end_line + + + 12 + + + 1 + 5 + 368 + + + 5 + 6 + 449 + 6 8 @@ -12227,52 +12775,52 @@ 8 10 - 492 + 507 10 13 - 537 + 572 13 17 - 530 + 555 17 22 - 530 + 559 22 29 - 506 + 524 29 39 - 534 + 538 39 52 - 471 + 477 52 76 - 464 + 480 76 150 - 471 + 477 150 - 1116 - 384 + 1135 + 388 @@ -12287,68 +12835,68 @@ 1 - 18 - 471 + 19 + 576 - 18 - 25 - 516 + 19 + 26 + 484 - 25 + 26 34 - 520 + 501 34 42 - 471 + 490 42 48 - 478 + 477 48 57 - 495 + 521 57 - 65 - 527 + 64 + 480 - 65 - 73 - 513 + 64 + 72 + 511 - 73 - 80 - 471 + 72 + 79 + 480 - 80 - 90 - 516 + 79 + 89 + 511 - 90 - 102 - 467 + 89 + 101 + 511 - 102 - 122 - 467 + 101 + 121 + 497 - 122 + 121 246 - 261 + 279 @@ -12364,67 +12912,72 @@ 1 2 - 359 + 371 2 - 9 - 401 + 8 + 163 - 9 - 21 - 377 + 8 + 11 + 344 - 21 - 35 - 356 + 11 + 23 + 344 - 35 - 72 - 345 + 23 + 39 + 344 - 72 - 108 - 349 + 39 + 77 + 344 - 108 - 147 - 345 + 77 + 114 + 340 - 147 - 196 - 352 + 114 + 154 + 340 - 196 - 258 - 342 + 154 + 208 + 340 - 258 - 418 - 342 + 208 + 287 + 344 - 422 - 861 - 342 + 287 + 482 + 344 - 862 - 2024 - 342 + 485 + 1012 + 340 - 2033 - 14015 - 300 + 1015 + 2889 + 340 + + + 2913 + 14685 + 221 @@ -12440,57 +12993,57 @@ 1 2 - 1194 + 1250 2 - 4 - 289 + 5 + 412 - 4 - 8 - 391 + 5 + 11 + 398 - 8 - 13 - 352 + 11 + 14 + 310 - 13 - 16 - 411 + 14 + 18 + 368 - 16 - 22 - 366 + 18 + 25 + 398 - 22 - 30 - 349 + 25 + 39 + 340 - 30 - 54 - 342 + 39 + 78 + 340 - 54 - 117 - 342 + 78 + 173 + 344 - 117 - 412 - 342 + 178 + 1184 + 340 - 419 - 1600 - 174 + 1187 + 1680 + 20 @@ -12506,67 +13059,72 @@ 1 2 - 359 + 374 2 - 6 + 5 + 146 + + + 5 + 8 + 357 + + + 8 + 16 398 - 6 - 14 - 356 + 16 + 25 + 340 - 14 - 20 - 345 + 25 + 39 + 347 - 20 - 34 - 356 + 39 + 49 + 357 - 34 - 46 - 359 + 49 + 59 + 351 - 46 - 55 - 349 + 59 + 71 + 351 - 55 - 66 - 373 + 71 + 80 + 354 - 66 - 76 - 366 + 80 + 93 + 354 - 76 - 87 - 352 + 93 + 114 + 340 - 87 - 105 - 349 + 114 + 163 + 344 - 105 - 133 - 352 - - - 133 + 163 220 - 237 + 105 @@ -12582,52 +13140,52 @@ 1 2 - 1124 + 1135 2 3 - 726 + 743 3 4 - 373 + 412 4 5 - 405 + 327 5 6 - 349 + 361 6 7 - 300 + 279 7 10 - 418 + 388 10 15 - 394 + 381 15 - 27 - 356 + 25 + 357 - 27 - 255 - 108 + 25 + 260 + 139 @@ -12643,67 +13201,72 @@ 1 2 - 359 + 374 2 - 7 - 418 + 6 + 170 - 7 - 15 - 377 + 6 + 9 + 385 - 15 - 23 - 356 + 9 + 17 + 391 - 23 - 38 - 345 + 17 + 28 + 340 - 38 - 50 - 356 + 28 + 43 + 340 - 50 - 59 - 373 + 43 + 53 + 361 - 59 - 70 - 363 + 53 + 64 + 364 - 70 - 80 - 359 + 64 + 75 + 347 - 80 - 92 - 356 + 75 + 84 + 340 - 92 - 110 - 345 + 84 + 97 + 340 - 110 - 143 - 342 + 97 + 120 + 347 - 144 + 120 + 174 + 351 + + + 175 222 - 202 + 68 @@ -12719,67 +13282,67 @@ 1 2 - 90 + 81 2 4 - 94 + 92 4 - 9 - 87 + 10 + 88 - 9 + 10 21 - 87 + 81 21 - 35 - 87 + 34 + 81 - 35 - 61 - 83 + 36 + 62 + 81 - 61 - 126 - 83 + 63 + 116 + 81 - 126 - 379 - 83 + 130 + 342 + 81 - 411 - 1283 - 83 + 369 + 1166 + 81 - 1340 - 3369 - 83 + 1182 + 2945 + 81 - 3425 - 7926 - 83 + 3082 + 7421 + 81 - 7934 - 10874 - 83 + 7778 + 11207 + 81 - 11325 - 39412 - 52 + 11280 + 41035 + 61 @@ -12795,442 +13358,447 @@ 1 2 - 136 + 126 2 4 - 87 + 85 4 9 - 83 + 81 9 - 16 - 87 + 17 + 88 - 16 - 26 - 83 + 17 + 27 + 81 - 26 - 51 - 83 + 27 + 55 + 85 - 51 - 117 - 83 + 56 + 125 + 81 - 120 - 294 - 83 + 125 + 305 + 81 - 302 - 565 - 83 + 317 + 585 + 81 - 572 - 956 - 83 + 598 + 998 + 81 - 1000 - 1165 - 83 + 1042 + 1223 + 81 - 1174 - 1249 - 83 + 1227 + 1315 + 85 - 1262 - 1473 + 1357 + 1550 + 17 + + + + + + + start_column + start_line + + + 12 + + + 1 + 2 + 112 + + + 2 + 4 + 85 + + + 4 + 9 + 81 + + + 9 + 17 + 85 + + + 17 + 27 + 78 + + + 27 + 44 + 81 + + + 44 + 85 + 81 + + + 85 + 177 + 81 + + + 186 + 351 + 81 + + + 354 + 553 + 81 + + + 553 + 759 + 81 + + + 760 + 810 + 81 + + + 810 + 1028 + 44 + + + + + + + start_column + end_line + + + 12 + + + 1 + 2 + 109 + + + 2 + 4 + 85 + + + 4 + 9 + 85 + + + 9 + 17 + 85 + + + 17 + 28 + 95 + + + 28 + 53 + 81 + + + 57 + 103 + 81 + + + 109 + 204 + 81 + + + 204 + 389 + 81 + + + 426 + 609 + 81 + + + 619 + 786 + 81 + + + 786 + 846 + 81 + + + 877 + 1028 + 27 + + + + + + + start_column + end_column + + + 12 + + + 1 + 2 + 109 + + + 2 + 3 + 68 + + + 3 + 5 + 81 + + + 5 + 9 + 81 + + + 9 + 12 + 85 + + + 12 + 19 + 95 + + + 19 + 27 + 88 + + + 27 + 43 + 81 + + + 43 + 66 + 81 + + + 66 + 89 + 85 + + + 90 + 121 + 85 + + + 126 + 149 + 81 + + + 149 + 187 + 34 + + + + + + + end_line + id + + + 12 + + + 1 + 3 + 102 + + + 3 + 4 + 340 + + + 4 + 8 + 344 + + + 8 + 21 + 374 + + + 21 + 35 + 340 + + + 35 + 71 + 340 + + + 71 + 106 + 340 + + + 106 + 146 + 340 + + + 146 + 202 + 340 + + + 202 + 264 + 344 + + + 264 + 433 + 340 + + + 436 + 889 + 340 + + + 891 + 2113 + 340 + + + 2173 + 13376 + 293 + + + + + + + end_line + file + + + 12 + + + 1 + 2 + 1250 + + + 2 + 5 + 412 + + + 5 + 11 + 398 + + + 11 + 14 + 310 + + + 14 + 18 + 368 + + + 18 + 25 + 398 + + + 25 + 39 + 340 + + + 39 + 78 + 340 + + + 78 + 173 + 344 + + + 178 + 1184 + 340 + + + 1188 + 1680 20 - - start_column - start_line - - - 12 - - - 1 - 2 - 125 - - - 2 - 4 - 73 - - - 4 - 8 - 87 - - - 8 - 16 - 87 - - - 16 - 25 - 87 - - - 25 - 47 - 83 - - - 49 - 85 - 87 - - - 86 - 188 - 83 - - - 192 - 363 - 83 - - - 375 - 570 - 83 - - - 577 - 763 - 83 - - - 763 - 809 - 83 - - - 819 - 1020 - 34 - - - - - - - start_column - end_line - - - 12 - - - 1 - 2 - 122 - - - 2 - 4 - 76 - - - 4 - 8 - 83 - - - 8 - 16 - 90 - - - 16 - 25 - 87 - - - 25 - 46 - 83 - - - 49 - 86 - 87 - - - 86 - 188 - 83 - - - 192 - 369 - 83 - - - 378 - 577 - 83 - - - 585 - 777 - 83 - - - 779 - 817 - 83 - - - 824 - 1020 - 34 - - - - - - - start_column - end_column - - - 12 - - - 1 - 2 - 115 - - - 2 - 3 - 62 - - - 3 - 5 - 87 - - - 5 - 9 - 94 - - - 9 - 12 - 87 - - - 12 - 19 - 94 - - - 19 - 25 - 83 - - - 26 - 42 - 83 - - - 42 - 64 - 83 - - - 66 - 88 - 83 - - - 89 - 118 - 87 - - - 118 - 145 - 87 - - - 146 - 188 - 34 - - - - - - - end_line - id - - - 12 - - - 1 - 4 - 418 - - - 4 - 9 - 349 - - - 9 - 21 - 356 - - - 21 - 34 - 359 - - - 34 - 70 - 345 - - - 70 - 109 - 356 - - - 109 - 147 - 349 - - - 147 - 195 - 349 - - - 195 - 258 - 349 - - - 259 - 426 - 342 - - - 427 - 881 - 342 - - - 886 - 2080 - 342 - - - 2088 - 12793 - 296 - - - - - - - end_line - file - - - 12 - - - 1 - 2 - 1194 - - - 2 - 4 - 289 - - - 4 - 8 - 391 - - - 8 - 13 - 352 - - - 13 - 16 - 411 - - - 16 - 22 - 366 - - - 22 - 30 - 349 - - - 30 - 54 - 342 - - - 54 - 117 - 342 - - - 117 - 412 - 342 - - - 419 - 1600 - 174 - - - - - end_line start_line @@ -13241,52 +13809,52 @@ 1 2 - 1036 + 1083 2 3 - 719 + 698 3 4 - 450 + 419 4 5 - 331 + 351 5 6 - 377 + 354 6 7 - 237 + 224 7 - 9 - 366 + 10 + 415 - 9 - 14 - 356 + 10 + 16 + 391 - 14 - 21 - 342 + 16 + 25 + 340 - 21 + 25 36 - 338 + 245 @@ -13307,67 +13875,67 @@ 2 3 - 394 + 419 3 - 7 - 359 + 6 + 340 - 7 - 15 - 359 + 6 + 14 + 340 - 15 - 22 - 359 + 14 + 21 + 351 - 22 - 37 - 363 + 21 + 36 + 351 - 37 - 49 - 373 + 36 + 47 + 357 - 49 + 47 57 - 352 + 361 57 68 - 342 + 347 68 - 78 - 370 + 77 + 347 - 78 + 77 89 - 359 + 368 89 - 108 - 352 + 106 + 340 - 108 - 141 - 345 + 106 + 137 + 344 - 141 + 138 220 - 195 + 228 @@ -13383,67 +13951,72 @@ 1 2 - 356 + 371 2 - 6 - 398 + 5 + 149 - 6 - 14 - 352 + 5 + 8 + 354 - 14 - 21 - 363 + 8 + 16 + 391 - 21 - 36 - 349 + 16 + 26 + 351 - 36 - 49 - 380 + 26 + 41 + 361 - 49 - 58 - 366 + 41 + 52 + 368 - 58 - 68 - 345 + 52 + 63 + 368 - 68 - 78 - 345 + 63 + 74 + 351 - 78 - 89 - 342 + 74 + 84 + 354 - 89 - 108 - 345 + 84 + 98 + 361 - 108 - 133 - 342 + 98 + 122 + 368 - 133 + 122 + 189 + 344 + + + 191 225 - 268 + 30 @@ -13458,68 +14031,73 @@ 1 - 3 - 97 + 2 + 57 - 3 - 6 - 97 + 2 + 5 + 85 - 6 - 15 - 90 + 5 + 10 + 85 - 15 - 30 - 90 + 10 + 22 + 81 - 30 - 51 - 83 + 22 + 33 + 81 - 51 - 97 - 83 + 33 + 64 + 85 - 97 - 222 - 83 + 64 + 130 + 81 - 224 - 762 - 83 + 131 + 339 + 81 - 762 - 2110 - 83 + 356 + 1222 + 81 - 2276 - 4746 - 83 + 1283 + 2975 + 81 - 5068 - 9429 - 83 + 3087 + 6873 + 81 - 9527 - 11084 - 83 + 7069 + 10622 + 81 - 11198 - 17883 - 48 + 10676 + 12015 + 81 + + + 12205 + 18687 + 20 @@ -13535,67 +14113,67 @@ 1 2 - 115 + 109 2 4 - 97 + 78 4 - 9 - 90 + 8 + 85 - 9 - 18 - 87 + 8 + 15 + 85 - 18 - 28 - 97 + 15 + 25 + 85 - 28 - 53 - 83 + 25 + 42 + 81 - 53 - 120 - 83 + 42 + 90 + 81 - 125 - 345 - 83 + 92 + 222 + 81 - 345 - 649 - 83 + 235 + 503 + 81 - 662 - 1049 - 83 + 558 + 952 + 81 - 1092 - 1225 - 87 + 959 + 1224 + 81 - 1228 - 1298 - 83 + 1233 + 1313 + 81 - 1302 - 1500 - 17 + 1314 + 1577 + 54 @@ -13611,67 +14189,67 @@ 1 2 - 104 + 98 2 4 - 90 + 81 4 8 - 83 + 92 8 - 15 - 83 + 16 + 85 - 15 - 24 - 83 + 16 + 26 + 85 - 24 - 42 - 87 + 26 + 46 + 88 - 42 - 81 - 87 + 46 + 92 + 85 - 83 - 173 - 83 + 94 + 194 + 81 - 183 - 342 - 83 + 204 + 364 + 81 - 344 - 541 - 83 + 384 + 582 + 81 - 549 - 753 - 83 + 586 + 789 + 81 - 762 - 815 - 83 + 789 + 827 + 81 - 815 - 948 - 55 + 827 + 949 + 44 @@ -13687,67 +14265,67 @@ 1 2 - 66 + 64 2 - 4 - 90 + 5 + 98 - 4 - 8 - 83 + 5 + 9 + 92 - 8 - 12 - 73 + 9 + 14 + 88 - 12 - 18 - 94 + 14 + 23 + 95 - 18 - 29 - 83 + 23 + 38 + 85 - 29 - 39 - 87 + 38 + 47 + 81 - 39 - 50 - 87 + 47 + 56 + 88 - 50 - 62 - 87 + 57 + 68 + 81 - 62 - 75 - 94 + 69 + 80 + 81 - 75 - 85 - 83 + 80 + 91 + 88 - 85 - 97 - 83 + 91 + 100 + 81 - 97 - 110 - 80 + 100 + 111 + 40 @@ -13763,67 +14341,67 @@ 1 2 - 108 + 102 2 4 - 87 + 81 4 8 - 83 + 88 8 16 - 87 + 88 16 - 25 - 87 + 26 + 85 - 25 - 43 - 83 + 26 + 46 + 85 - 43 - 80 - 83 + 46 + 91 + 85 - 80 - 182 - 83 + 92 + 205 + 81 - 182 - 337 - 83 + 206 + 363 + 81 - 342 - 540 - 83 + 381 + 569 + 81 - 540 - 753 - 83 + 581 + 789 + 81 - 761 - 815 - 83 + 789 + 827 + 81 - 815 - 899 - 55 + 827 + 906 + 44 @@ -13833,11 +14411,11 @@ method_child - 80492 + 81847 method - 29655 + 30153 index @@ -13845,7 +14423,7 @@ child - 80492 + 81847 @@ -13859,32 +14437,32 @@ 1 2 - 13358 + 13610 2 3 - 5509 + 5547 3 4 - 3801 + 3895 4 5 - 2370 + 2405 5 7 - 2495 + 2533 7 77 - 2122 + 2163 @@ -13900,32 +14478,32 @@ 1 2 - 13358 + 13610 2 3 - 5509 + 5547 3 4 - 3801 + 3895 4 5 - 2370 + 2405 5 7 - 2495 + 2533 7 77 - 2122 + 2163 @@ -13956,46 +14534,46 @@ 5 6 - 11 + 10 6 7 - 6 + 7 7 - 10 + 12 5 13 - 20 + 19 6 20 - 35 + 36 6 - 42 - 113 + 43 + 114 6 - 147 - 397 + 148 + 401 6 - 495 - 2123 + 501 + 2164 6 - 3096 - 29656 + 3155 + 30154 6 @@ -14027,46 +14605,46 @@ 5 6 - 11 + 10 6 7 - 6 + 7 7 - 10 + 12 5 13 - 20 + 19 6 20 - 35 + 36 6 - 42 - 113 + 43 + 114 6 - 147 - 397 + 148 + 401 6 - 495 - 2123 + 501 + 2164 6 - 3096 - 29656 + 3155 + 30154 6 @@ -14083,7 +14661,7 @@ 1 2 - 80492 + 81847 @@ -14099,7 +14677,7 @@ 1 2 - 80492 + 81847 @@ -14109,19 +14687,19 @@ method_def - 29945 + 30455 id - 29945 + 30455 name - 29945 + 30455 loc - 29945 + 30455 @@ -14135,7 +14713,7 @@ 1 2 - 29945 + 30455 @@ -14151,7 +14729,7 @@ 1 2 - 29945 + 30455 @@ -14167,7 +14745,7 @@ 1 2 - 29945 + 30455 @@ -14183,7 +14761,7 @@ 1 2 - 29945 + 30455 @@ -14199,7 +14777,7 @@ 1 2 - 29945 + 30455 @@ -14215,7 +14793,7 @@ 1 2 - 29945 + 30455 @@ -14225,15 +14803,15 @@ method_parameters - 8177 + 8396 method - 8177 + 8396 parameters - 8177 + 8396 @@ -14247,7 +14825,7 @@ 1 2 - 8177 + 8396 @@ -14263,7 +14841,7 @@ 1 2 - 8177 + 8396 @@ -14273,11 +14851,11 @@ method_parameters_child - 14256 + 14612 method_parameters - 8631 + 8834 index @@ -14285,7 +14863,7 @@ child - 14256 + 14612 @@ -14299,22 +14877,22 @@ 1 2 - 5191 + 5307 2 3 - 2126 + 2176 3 4 - 827 + 851 4 12 - 487 + 500 @@ -14330,22 +14908,22 @@ 1 2 - 5191 + 5307 2 3 - 2126 + 2176 3 4 - 827 + 851 4 12 - 487 + 500 @@ -14374,43 +14952,43 @@ 1 - 24 - 25 + 25 + 26 1 - 40 - 41 + 44 + 45 1 - 91 - 92 + 96 + 97 1 - 212 - 213 + 218 + 219 1 - 487 - 488 + 500 + 501 1 - 1314 - 1315 + 1351 + 1352 1 - 3440 - 3441 + 3527 + 3528 1 - 8631 - 8632 + 8834 + 8835 1 @@ -14440,43 +15018,43 @@ 1 - 24 - 25 + 25 + 26 1 - 40 - 41 + 44 + 45 1 - 91 - 92 + 96 + 97 1 - 212 - 213 + 218 + 219 1 - 487 - 488 + 500 + 501 1 - 1314 - 1315 + 1351 + 1352 1 - 3440 - 3441 + 3527 + 3528 1 - 8631 - 8632 + 8834 + 8835 1 @@ -14493,7 +15071,7 @@ 1 2 - 14256 + 14612 @@ -14509,7 +15087,7 @@ 1 2 - 14256 + 14612 @@ -14519,15 +15097,15 @@ method_parameters_def - 8700 + 8920 id - 8700 + 8920 loc - 8700 + 8920 @@ -14541,7 +15119,7 @@ 1 2 - 8700 + 8920 @@ -14557,7 +15135,7 @@ 1 2 - 8700 + 8920 @@ -14567,19 +15145,19 @@ module_child - 9449 + 9655 module - 3196 + 3290 index - 117 + 119 child - 9449 + 9655 @@ -14593,27 +15171,27 @@ 1 2 - 2270 + 2339 2 3 - 268 + 275 3 5 - 227 + 237 5 11 - 254 + 259 11 - 118 - 177 + 120 + 180 @@ -14629,27 +15207,27 @@ 1 2 - 2270 + 2339 2 3 - 268 + 275 3 5 - 227 + 237 5 11 - 254 + 259 11 - 118 - 177 + 120 + 180 @@ -14665,7 +15243,7 @@ 1 2 - 6 + 8 2 @@ -14675,12 +15253,12 @@ 3 4 - 26 + 25 4 6 - 10 + 11 6 @@ -14689,38 +15267,38 @@ 9 - 15 + 14 9 - 16 + 15 23 10 23 - 34 - 10 - - - 36 - 80 + 35 9 - 83 - 178 + 35 + 73 9 - 197 - 927 + 79 + 166 9 - 3196 - 3197 - 1 + 180 + 677 + 9 + + + 951 + 3291 + 2 @@ -14736,7 +15314,7 @@ 1 2 - 6 + 8 2 @@ -14746,12 +15324,12 @@ 3 4 - 26 + 25 4 6 - 10 + 11 6 @@ -14760,38 +15338,38 @@ 9 - 15 + 14 9 - 16 + 15 23 10 23 - 34 - 10 - - - 36 - 80 + 35 9 - 83 - 178 + 35 + 73 9 - 197 - 927 + 79 + 166 9 - 3196 - 3197 - 1 + 180 + 677 + 9 + + + 951 + 3291 + 2 @@ -14807,7 +15385,7 @@ 1 2 - 9449 + 9655 @@ -14823,7 +15401,7 @@ 1 2 - 9449 + 9655 @@ -14833,19 +15411,19 @@ module_def - 4029 + 4441 id - 4029 + 4441 name - 4029 + 4441 loc - 4029 + 4441 @@ -14859,7 +15437,7 @@ 1 2 - 4029 + 4441 @@ -14875,7 +15453,7 @@ 1 2 - 4029 + 4441 @@ -14891,7 +15469,7 @@ 1 2 - 4029 + 4441 @@ -14907,7 +15485,7 @@ 1 2 - 4029 + 4441 @@ -14923,7 +15501,7 @@ 1 2 - 4029 + 4441 @@ -14939,7 +15517,7 @@ 1 2 - 4029 + 4441 @@ -14997,15 +15575,15 @@ next_def - 620 + 653 id - 620 + 653 loc - 620 + 653 @@ -15019,7 +15597,7 @@ 1 2 - 620 + 653 @@ -15035,7 +15613,7 @@ 1 2 - 620 + 653 @@ -15189,15 +15767,15 @@ operator_assignment_def - 1971 + 2002 id - 1971 + 2002 left - 1971 + 2002 operator @@ -15205,11 +15783,11 @@ right - 1971 + 2002 loc - 1971 + 2002 @@ -15223,7 +15801,7 @@ 1 2 - 1971 + 2002 @@ -15239,7 +15817,7 @@ 1 2 - 1971 + 2002 @@ -15255,7 +15833,7 @@ 1 2 - 1971 + 2002 @@ -15271,7 +15849,7 @@ 1 2 - 1971 + 2002 @@ -15287,7 +15865,7 @@ 1 2 - 1971 + 2002 @@ -15303,7 +15881,7 @@ 1 2 - 1971 + 2002 @@ -15319,7 +15897,7 @@ 1 2 - 1971 + 2002 @@ -15335,7 +15913,7 @@ 1 2 - 1971 + 2002 @@ -15369,13 +15947,13 @@ 1 - 470 - 471 + 495 + 496 1 - 1371 - 1372 + 1385 + 1386 1 @@ -15410,13 +15988,13 @@ 1 - 470 - 471 + 495 + 496 1 - 1371 - 1372 + 1385 + 1386 1 @@ -15451,13 +16029,13 @@ 1 - 470 - 471 + 495 + 496 1 - 1371 - 1372 + 1385 + 1386 1 @@ -15492,13 +16070,13 @@ 1 - 470 - 471 + 495 + 496 1 - 1371 - 1372 + 1385 + 1386 1 @@ -15515,7 +16093,7 @@ 1 2 - 1971 + 2002 @@ -15531,7 +16109,7 @@ 1 2 - 1971 + 2002 @@ -15547,7 +16125,7 @@ 1 2 - 1971 + 2002 @@ -15563,7 +16141,7 @@ 1 2 - 1971 + 2002 @@ -15579,7 +16157,7 @@ 1 2 - 1971 + 2002 @@ -15595,7 +16173,7 @@ 1 2 - 1971 + 2002 @@ -15611,7 +16189,7 @@ 1 2 - 1971 + 2002 @@ -15627,7 +16205,7 @@ 1 2 - 1971 + 2002 @@ -15637,23 +16215,23 @@ optional_parameter_def - 2031 + 2047 id - 2031 + 2047 name - 2031 + 2047 value - 2031 + 2047 loc - 2031 + 2047 @@ -15667,7 +16245,7 @@ 1 2 - 2031 + 2047 @@ -15683,7 +16261,7 @@ 1 2 - 2031 + 2047 @@ -15699,7 +16277,7 @@ 1 2 - 2031 + 2047 @@ -15715,7 +16293,7 @@ 1 2 - 2031 + 2047 @@ -15731,7 +16309,7 @@ 1 2 - 2031 + 2047 @@ -15747,7 +16325,7 @@ 1 2 - 2031 + 2047 @@ -15763,7 +16341,7 @@ 1 2 - 2031 + 2047 @@ -15779,7 +16357,7 @@ 1 2 - 2031 + 2047 @@ -15795,7 +16373,7 @@ 1 2 - 2031 + 2047 @@ -15811,7 +16389,7 @@ 1 2 - 2031 + 2047 @@ -15827,7 +16405,7 @@ 1 2 - 2031 + 2047 @@ -15843,7 +16421,7 @@ 1 2 - 2031 + 2047 @@ -15853,23 +16431,23 @@ pair_def - 59815 + 62127 id - 59815 + 62127 key__ - 59815 + 62127 value - 59815 + 62127 loc - 59815 + 62127 @@ -15883,7 +16461,7 @@ 1 2 - 59815 + 62127 @@ -15899,7 +16477,7 @@ 1 2 - 59815 + 62127 @@ -15915,7 +16493,7 @@ 1 2 - 59815 + 62127 @@ -15931,7 +16509,7 @@ 1 2 - 59815 + 62127 @@ -15947,7 +16525,7 @@ 1 2 - 59815 + 62127 @@ -15963,7 +16541,7 @@ 1 2 - 59815 + 62127 @@ -15979,7 +16557,7 @@ 1 2 - 59815 + 62127 @@ -15995,7 +16573,7 @@ 1 2 - 59815 + 62127 @@ -16011,7 +16589,7 @@ 1 2 - 59815 + 62127 @@ -16027,7 +16605,7 @@ 1 2 - 59815 + 62127 @@ -16043,7 +16621,7 @@ 1 2 - 59815 + 62127 @@ -16059,7 +16637,7 @@ 1 2 - 59815 + 62127 @@ -16069,11 +16647,11 @@ parenthesized_statements_child - 1647 + 1653 parenthesized_statements - 1646 + 1652 index @@ -16081,7 +16659,7 @@ child - 1647 + 1653 @@ -16095,7 +16673,7 @@ 1 2 - 1645 + 1651 2 @@ -16116,7 +16694,7 @@ 1 2 - 1645 + 1651 2 @@ -16140,8 +16718,8 @@ 1 - 1601 - 1602 + 1614 + 1615 1 @@ -16161,8 +16739,8 @@ 1 - 1601 - 1602 + 1614 + 1615 1 @@ -16179,7 +16757,7 @@ 1 2 - 1647 + 1653 @@ -16195,7 +16773,7 @@ 1 2 - 1647 + 1653 @@ -16205,15 +16783,15 @@ parenthesized_statements_def - 1646 + 1652 id - 1646 + 1652 loc - 1646 + 1652 @@ -16227,7 +16805,7 @@ 1 2 - 1646 + 1652 @@ -16243,7 +16821,7 @@ 1 2 - 1646 + 1652 @@ -16253,19 +16831,19 @@ pattern_def - 1171 + 1186 id - 1171 + 1186 child - 1171 + 1186 loc - 1171 + 1186 @@ -16279,7 +16857,7 @@ 1 2 - 1171 + 1186 @@ -16295,7 +16873,7 @@ 1 2 - 1171 + 1186 @@ -16311,7 +16889,7 @@ 1 2 - 1171 + 1186 @@ -16327,7 +16905,7 @@ 1 2 - 1171 + 1186 @@ -16343,7 +16921,7 @@ 1 2 - 1171 + 1186 @@ -16359,7 +16937,7 @@ 1 2 - 1171 + 1186 @@ -16369,11 +16947,11 @@ program_child - 14304 + 14591 program - 6106 + 6251 index @@ -16381,7 +16959,7 @@ child - 14304 + 14591 @@ -16395,27 +16973,27 @@ 1 2 - 3194 + 3289 2 3 - 1599 + 1625 3 4 - 488 + 504 4 7 - 481 + 484 7 - 41 - 342 + 42 + 347 @@ -16431,27 +17009,27 @@ 1 2 - 3194 + 3289 2 3 - 1599 + 1625 3 4 - 488 + 504 4 7 - 481 + 484 7 - 41 - 342 + 42 + 347 @@ -16467,7 +17045,7 @@ 1 2 - 27 + 30 2 @@ -16481,48 +17059,43 @@ 5 - 6 - 3 - - - 7 8 10 - 9 + 8 12 10 - 13 - 19 + 12 + 20 10 - 29 - 39 + 20 + 34 10 - 47 - 74 + 41 + 58 10 - 84 - 131 + 76 + 103 10 - 175 - 377 + 135 + 245 10 - 834 - 1750 - 6 + 392 + 1835 + 10 @@ -16538,7 +17111,7 @@ 1 2 - 27 + 30 2 @@ -16552,48 +17125,43 @@ 5 - 6 - 3 - - - 7 8 10 - 9 + 8 12 10 - 13 - 19 + 12 + 20 10 - 29 - 39 + 20 + 34 10 - 47 - 74 + 41 + 58 10 - 84 - 131 + 76 + 103 10 - 175 - 377 + 135 + 245 10 - 834 - 1750 - 6 + 392 + 1835 + 10 @@ -16609,7 +17177,7 @@ 1 2 - 14304 + 14591 @@ -16625,7 +17193,7 @@ 1 2 - 14304 + 14591 @@ -16635,15 +17203,15 @@ program_def - 6179 + 6322 id - 6179 + 6322 loc - 6179 + 6322 @@ -16657,7 +17225,7 @@ 1 2 - 6179 + 6322 @@ -16673,7 +17241,7 @@ 1 2 - 6179 + 6322 @@ -16683,15 +17251,15 @@ range_begin - 531 + 539 range - 531 + 539 begin - 531 + 539 @@ -16705,7 +17273,7 @@ 1 2 - 531 + 539 @@ -16721,7 +17289,7 @@ 1 2 - 531 + 539 @@ -16731,11 +17299,11 @@ range_def - 538 + 546 id - 538 + 546 operator @@ -16743,7 +17311,7 @@ loc - 538 + 546 @@ -16757,7 +17325,7 @@ 1 2 - 538 + 546 @@ -16773,7 +17341,7 @@ 1 2 - 538 + 546 @@ -16792,8 +17360,8 @@ 1 - 416 - 417 + 424 + 425 1 @@ -16813,8 +17381,8 @@ 1 - 416 - 417 + 424 + 425 1 @@ -16831,7 +17399,7 @@ 1 2 - 538 + 546 @@ -16847,7 +17415,7 @@ 1 2 - 538 + 546 @@ -16857,15 +17425,15 @@ range_end - 461 + 463 range - 461 + 463 end - 461 + 463 @@ -16879,7 +17447,7 @@ 1 2 - 461 + 463 @@ -16895,7 +17463,7 @@ 1 2 - 461 + 463 @@ -17111,11 +17679,11 @@ regex_child - 13384 + 13433 regex - 3944 + 3974 index @@ -17123,7 +17691,7 @@ child - 13384 + 13433 @@ -17137,7 +17705,7 @@ 1 2 - 2015 + 2038 2 @@ -17147,32 +17715,32 @@ 3 4 - 523 + 522 4 5 - 149 + 152 5 6 - 332 + 337 6 8 - 320 + 317 8 16 - 309 + 313 16 44 - 76 + 75 @@ -17188,7 +17756,7 @@ 1 2 - 2015 + 2038 2 @@ -17198,32 +17766,32 @@ 3 4 - 523 + 522 4 5 - 149 + 152 5 6 - 332 + 337 6 8 - 320 + 317 8 16 - 309 + 313 16 44 - 76 + 75 @@ -17283,32 +17851,32 @@ 58 - 95 + 94 3 - 106 - 165 + 104 + 163 3 - 223 - 326 + 221 + 328 3 - 385 + 388 706 3 - 1037 - 1710 + 1042 + 1717 3 - 1929 - 3945 + 1936 + 3975 2 @@ -17369,32 +17937,32 @@ 58 - 95 + 94 3 - 106 - 165 + 104 + 163 3 - 223 - 326 + 221 + 328 3 - 385 + 388 706 3 - 1037 - 1710 + 1042 + 1717 3 - 1929 - 3945 + 1936 + 3975 2 @@ -17411,7 +17979,7 @@ 1 2 - 13384 + 13433 @@ -17427,7 +17995,7 @@ 1 2 - 13384 + 13433 @@ -17437,15 +18005,15 @@ regex_def - 3949 + 3979 id - 3949 + 3979 loc - 3949 + 3979 @@ -17459,7 +18027,7 @@ 1 2 - 3949 + 3979 @@ -17475,7 +18043,7 @@ 1 2 - 3949 + 3979 @@ -17485,15 +18053,15 @@ rescue_body - 521 + 539 rescue - 521 + 539 body - 521 + 539 @@ -17507,7 +18075,7 @@ 1 2 - 521 + 539 @@ -17523,7 +18091,7 @@ 1 2 - 521 + 539 @@ -17533,15 +18101,15 @@ rescue_def - 616 + 634 id - 616 + 634 loc - 616 + 634 @@ -17555,7 +18123,7 @@ 1 2 - 616 + 634 @@ -17571,7 +18139,7 @@ 1 2 - 616 + 634 @@ -17581,15 +18149,15 @@ rescue_exceptions - 416 + 429 rescue - 416 + 429 exceptions - 416 + 429 @@ -17603,7 +18171,7 @@ 1 2 - 416 + 429 @@ -17619,7 +18187,7 @@ 1 2 - 416 + 429 @@ -17629,23 +18197,23 @@ rescue_modifier_def - 171 + 174 id - 171 + 174 body - 171 + 174 handler - 171 + 174 loc - 171 + 174 @@ -17659,7 +18227,7 @@ 1 2 - 171 + 174 @@ -17675,7 +18243,7 @@ 1 2 - 171 + 174 @@ -17691,7 +18259,7 @@ 1 2 - 171 + 174 @@ -17707,7 +18275,7 @@ 1 2 - 171 + 174 @@ -17723,7 +18291,7 @@ 1 2 - 171 + 174 @@ -17739,7 +18307,7 @@ 1 2 - 171 + 174 @@ -17755,7 +18323,7 @@ 1 2 - 171 + 174 @@ -17771,7 +18339,7 @@ 1 2 - 171 + 174 @@ -17787,7 +18355,7 @@ 1 2 - 171 + 174 @@ -17803,7 +18371,7 @@ 1 2 - 171 + 174 @@ -17819,7 +18387,7 @@ 1 2 - 171 + 174 @@ -17835,7 +18403,7 @@ 1 2 - 171 + 174 @@ -17845,15 +18413,15 @@ rescue_variable - 298 + 309 rescue - 298 + 309 variable - 298 + 309 @@ -17867,7 +18435,7 @@ 1 2 - 298 + 309 @@ -17883,7 +18451,7 @@ 1 2 - 298 + 309 @@ -17941,15 +18509,15 @@ rest_assignment_def - 17 + 18 id - 17 + 18 loc - 17 + 18 @@ -17963,7 +18531,7 @@ 1 2 - 17 + 18 @@ -17979,7 +18547,7 @@ 1 2 - 17 + 18 @@ -18085,15 +18653,15 @@ return_child - 1584 + 1611 return - 1584 + 1611 child - 1584 + 1611 @@ -18107,7 +18675,7 @@ 1 2 - 1584 + 1611 @@ -18123,7 +18691,7 @@ 1 2 - 1584 + 1611 @@ -18133,15 +18701,15 @@ return_def - 2548 + 2601 id - 2548 + 2601 loc - 2548 + 2601 @@ -18155,7 +18723,7 @@ 1 2 - 2548 + 2601 @@ -18171,7 +18739,7 @@ 1 2 - 2548 + 2601 @@ -18181,11 +18749,11 @@ right_assignment_list_child - 861 + 880 right_assignment_list - 407 + 414 index @@ -18193,7 +18761,7 @@ child - 861 + 880 @@ -18207,12 +18775,12 @@ 2 3 - 372 + 374 3 5 - 33 + 38 5 @@ -18233,12 +18801,12 @@ 2 3 - 372 + 374 3 5 - 33 + 38 5 @@ -18267,13 +18835,13 @@ 1 - 35 - 36 + 40 + 41 1 - 407 - 408 + 414 + 415 2 @@ -18298,13 +18866,13 @@ 1 - 35 - 36 + 40 + 41 1 - 407 - 408 + 414 + 415 2 @@ -18321,7 +18889,7 @@ 1 2 - 861 + 880 @@ -18337,7 +18905,7 @@ 1 2 - 861 + 880 @@ -18347,15 +18915,15 @@ right_assignment_list_def - 407 + 414 id - 407 + 414 loc - 407 + 414 @@ -18369,7 +18937,7 @@ 1 2 - 407 + 414 @@ -18385,7 +18953,7 @@ 1 2 - 407 + 414 @@ -18395,19 +18963,19 @@ scope_resolution_def - 22240 + 22918 id - 22240 + 22918 name - 22240 + 22918 loc - 22240 + 22918 @@ -18421,7 +18989,7 @@ 1 2 - 22240 + 22918 @@ -18437,7 +19005,7 @@ 1 2 - 22240 + 22918 @@ -18453,7 +19021,7 @@ 1 2 - 22240 + 22918 @@ -18469,7 +19037,7 @@ 1 2 - 22240 + 22918 @@ -18485,7 +19053,7 @@ 1 2 - 22240 + 22918 @@ -18501,7 +19069,7 @@ 1 2 - 22240 + 22918 @@ -18511,15 +19079,15 @@ scope_resolution_scope - 21758 + 22255 scope_resolution - 21758 + 22255 scope - 21758 + 22255 @@ -18533,7 +19101,7 @@ 1 2 - 21758 + 22255 @@ -18549,7 +19117,7 @@ 1 2 - 21758 + 22255 @@ -18559,19 +19127,19 @@ setter_def - 181 + 186 id - 181 + 186 name - 181 + 186 loc - 181 + 186 @@ -18585,7 +19153,7 @@ 1 2 - 181 + 186 @@ -18601,7 +19169,7 @@ 1 2 - 181 + 186 @@ -18617,7 +19185,7 @@ 1 2 - 181 + 186 @@ -18633,7 +19201,7 @@ 1 2 - 181 + 186 @@ -18649,7 +19217,7 @@ 1 2 - 181 + 186 @@ -18665,7 +19233,7 @@ 1 2 - 181 + 186 @@ -18675,11 +19243,11 @@ singleton_class_child - 714 + 731 singleton_class - 185 + 191 index @@ -18687,7 +19255,7 @@ child - 714 + 731 @@ -18701,12 +19269,12 @@ 1 2 - 83 + 89 2 3 - 23 + 21 3 @@ -18716,17 +19284,17 @@ 4 5 - 16 + 15 5 6 - 10 + 11 6 8 - 15 + 17 8 @@ -18752,12 +19320,12 @@ 1 2 - 83 + 89 2 3 - 23 + 21 3 @@ -18767,17 +19335,17 @@ 4 5 - 16 + 15 5 6 - 10 + 11 6 8 - 15 + 17 8 @@ -18827,7 +19395,7 @@ 12 - 17 + 18 2 @@ -18836,28 +19404,28 @@ 2 - 21 + 22 27 2 33 - 42 + 44 2 - 51 - 68 + 54 + 70 2 - 79 + 81 103 2 - 185 - 186 + 191 + 192 1 @@ -18898,7 +19466,7 @@ 12 - 17 + 18 2 @@ -18907,28 +19475,28 @@ 2 - 21 + 22 27 2 33 - 42 + 44 2 - 51 - 68 + 54 + 70 2 - 79 + 81 103 2 - 185 - 186 + 191 + 192 1 @@ -18945,7 +19513,7 @@ 1 2 - 714 + 731 @@ -18961,7 +19529,7 @@ 1 2 - 714 + 731 @@ -18971,19 +19539,19 @@ singleton_class_def - 185 + 191 id - 185 + 191 value - 185 + 191 loc - 185 + 191 @@ -18997,7 +19565,7 @@ 1 2 - 185 + 191 @@ -19013,7 +19581,7 @@ 1 2 - 185 + 191 @@ -19029,7 +19597,7 @@ 1 2 - 185 + 191 @@ -19045,7 +19613,7 @@ 1 2 - 185 + 191 @@ -19061,7 +19629,7 @@ 1 2 - 185 + 191 @@ -19077,7 +19645,7 @@ 1 2 - 185 + 191 @@ -19087,11 +19655,11 @@ singleton_method_child - 4960 + 5021 singleton_method - 1996 + 2020 index @@ -19099,7 +19667,7 @@ child - 4960 + 5021 @@ -19113,32 +19681,32 @@ 1 2 - 1124 + 1132 2 3 - 299 + 308 3 4 - 176 + 180 4 5 - 125 + 126 5 8 - 155 + 159 8 28 - 115 + 113 @@ -19154,32 +19722,32 @@ 1 2 - 1124 + 1132 2 3 - 299 + 308 3 4 - 176 + 180 4 5 - 125 + 126 5 8 - 155 + 159 8 28 - 115 + 113 @@ -19193,7 +19761,7 @@ 12 - 2 + 3 4 2 @@ -19209,52 +19777,52 @@ 7 - 8 + 9 2 - 10 - 15 + 11 + 16 2 - 20 - 25 + 22 + 27 2 30 - 38 + 37 2 48 - 65 + 64 2 87 - 113 + 112 2 - 141 - 191 + 142 + 195 2 - 263 - 386 + 267 + 392 2 - 557 - 849 + 567 + 869 2 - 1941 - 1942 + 1974 + 1975 1 @@ -19269,7 +19837,7 @@ 12 - 2 + 3 4 2 @@ -19285,52 +19853,52 @@ 7 - 8 + 9 2 - 10 - 15 + 11 + 16 2 - 20 - 25 + 22 + 27 2 30 - 38 + 37 2 48 - 65 + 64 2 87 - 113 + 112 2 - 141 - 191 + 142 + 195 2 - 263 - 386 + 267 + 392 2 - 557 - 849 + 567 + 869 2 - 1941 - 1942 + 1974 + 1975 1 @@ -19347,7 +19915,7 @@ 1 2 - 4960 + 5021 @@ -19363,7 +19931,7 @@ 1 2 - 4960 + 5021 @@ -19373,23 +19941,23 @@ singleton_method_def - 1996 + 2020 id - 1996 + 2020 name - 1996 + 2020 object - 1996 + 2020 loc - 1996 + 2020 @@ -19403,7 +19971,7 @@ 1 2 - 1996 + 2020 @@ -19419,7 +19987,7 @@ 1 2 - 1996 + 2020 @@ -19435,7 +20003,7 @@ 1 2 - 1996 + 2020 @@ -19451,7 +20019,7 @@ 1 2 - 1996 + 2020 @@ -19467,7 +20035,7 @@ 1 2 - 1996 + 2020 @@ -19483,7 +20051,7 @@ 1 2 - 1996 + 2020 @@ -19499,7 +20067,7 @@ 1 2 - 1996 + 2020 @@ -19515,7 +20083,7 @@ 1 2 - 1996 + 2020 @@ -19531,7 +20099,7 @@ 1 2 - 1996 + 2020 @@ -19547,7 +20115,7 @@ 1 2 - 1996 + 2020 @@ -19563,7 +20131,7 @@ 1 2 - 1996 + 2020 @@ -19579,7 +20147,7 @@ 1 2 - 1996 + 2020 @@ -19589,15 +20157,15 @@ singleton_method_parameters - 1250 + 1272 singleton_method - 1250 + 1272 parameters - 1250 + 1272 @@ -19611,7 +20179,7 @@ 1 2 - 1250 + 1272 @@ -19627,7 +20195,7 @@ 1 2 - 1250 + 1272 @@ -19648,19 +20216,19 @@ splat_argument_def - 693 + 683 id - 693 + 683 child - 693 + 683 loc - 693 + 683 @@ -19674,7 +20242,7 @@ 1 2 - 693 + 683 @@ -19690,7 +20258,7 @@ 1 2 - 693 + 683 @@ -19706,7 +20274,7 @@ 1 2 - 693 + 683 @@ -19722,7 +20290,7 @@ 1 2 - 693 + 683 @@ -19738,7 +20306,7 @@ 1 2 - 693 + 683 @@ -19754,7 +20322,7 @@ 1 2 - 693 + 683 @@ -19764,15 +20332,15 @@ splat_parameter_def - 932 + 921 id - 932 + 921 loc - 932 + 921 @@ -19786,7 +20354,7 @@ 1 2 - 932 + 921 @@ -19802,7 +20370,7 @@ 1 2 - 932 + 921 @@ -19812,15 +20380,15 @@ splat_parameter_name - 755 + 748 splat_parameter - 755 + 748 name - 755 + 748 @@ -19834,7 +20402,7 @@ 1 2 - 755 + 748 @@ -19850,7 +20418,7 @@ 1 2 - 755 + 748 @@ -19860,11 +20428,11 @@ string_array_child - 2973 + 3009 string_array - 923 + 932 index @@ -19872,7 +20440,7 @@ child - 2973 + 3009 @@ -19886,17 +20454,17 @@ 1 2 - 199 + 200 2 3 - 297 + 300 3 4 - 239 + 241 4 @@ -19906,12 +20474,12 @@ 5 8 - 70 + 71 8 89 - 52 + 54 @@ -19927,17 +20495,17 @@ 1 2 - 199 + 200 2 3 - 297 + 300 3 4 - 239 + 241 4 @@ -19947,12 +20515,12 @@ 5 8 - 70 + 71 8 89 - 52 + 54 @@ -19997,12 +20565,12 @@ 33 - 123 + 126 7 - 188 - 924 + 191 + 933 4 @@ -20048,12 +20616,12 @@ 33 - 123 + 126 7 - 188 - 924 + 191 + 933 4 @@ -20070,7 +20638,7 @@ 1 2 - 2973 + 3009 @@ -20086,7 +20654,7 @@ 1 2 - 2973 + 3009 @@ -20096,15 +20664,15 @@ string_array_def - 929 + 938 id - 929 + 938 loc - 929 + 938 @@ -20118,7 +20686,7 @@ 1 2 - 929 + 938 @@ -20134,7 +20702,7 @@ 1 2 - 929 + 938 @@ -20144,11 +20712,11 @@ string_child - 122691 + 124227 string__ - 88786 + 90152 index @@ -20156,7 +20724,7 @@ child - 122691 + 124227 @@ -20170,17 +20738,17 @@ 1 2 - 81977 + 83280 2 - 51 - 6665 + 63 + 6791 - 52 + 64 125 - 144 + 81 @@ -20196,17 +20764,17 @@ 1 2 - 81977 + 83280 2 - 51 - 6665 + 63 + 6791 - 52 + 64 125 - 144 + 81 @@ -20256,22 +20824,22 @@ 209 - 351 + 352 10 - 380 - 463 + 381 + 465 10 - 468 - 3413 + 470 + 3443 10 - 6809 - 88787 + 6872 + 90153 2 @@ -20322,22 +20890,22 @@ 209 - 351 + 352 10 - 380 - 463 + 381 + 465 10 - 468 - 3413 + 470 + 3443 10 - 6809 - 88787 + 6872 + 90153 2 @@ -20354,7 +20922,7 @@ 1 2 - 122691 + 124227 @@ -20370,7 +20938,7 @@ 1 2 - 122691 + 124227 @@ -20380,15 +20948,15 @@ string_def - 89867 + 91253 id - 89867 + 91253 loc - 89867 + 91253 @@ -20402,7 +20970,7 @@ 1 2 - 89867 + 91253 @@ -20418,7 +20986,7 @@ 1 2 - 89867 + 91253 @@ -20428,19 +20996,19 @@ subshell_child - 201 + 214 subshell - 129 + 83 index - 11 + 8 child - 201 + 214 @@ -20454,23 +21022,33 @@ 1 2 - 99 + 29 2 3 - 16 + 9 3 - 6 - 8 + 4 + 30 - 6 - 12 + 4 + 5 6 + + 5 + 8 + 7 + + + 8 + 9 + 1 + @@ -20485,23 +21063,33 @@ 1 2 - 99 + 29 2 3 - 16 + 9 3 - 6 - 8 + 4 + 30 - 6 - 12 + 4 + 5 6 + + 5 + 8 + 7 + + + 8 + 9 + 1 + @@ -20516,26 +21104,21 @@ 1 2 - 4 - - - 2 - 3 1 - 6 - 7 + 3 + 4 1 - 7 - 8 + 5 + 6 1 - 9 - 10 + 8 + 9 1 @@ -20544,13 +21127,18 @@ 1 - 30 - 31 + 44 + 45 1 - 129 - 130 + 53 + 54 + 1 + + + 82 + 83 1 @@ -20567,26 +21155,21 @@ 1 2 - 4 - - - 2 - 3 1 - 6 - 7 + 3 + 4 1 - 7 - 8 + 5 + 6 1 - 9 - 10 + 8 + 9 1 @@ -20595,13 +21178,18 @@ 1 - 30 - 31 + 44 + 45 1 - 129 - 130 + 53 + 54 + 1 + + + 82 + 83 1 @@ -20618,7 +21206,7 @@ 1 2 - 201 + 214 @@ -20634,7 +21222,7 @@ 1 2 - 201 + 214 @@ -20644,15 +21232,15 @@ subshell_def - 129 + 130 id - 129 + 130 loc - 129 + 130 @@ -20666,7 +21254,7 @@ 1 2 - 129 + 130 @@ -20682,7 +21270,7 @@ 1 2 - 129 + 130 @@ -20692,19 +21280,19 @@ superclass_def - 4039 + 4108 id - 4039 + 4108 child - 4039 + 4108 loc - 4039 + 4108 @@ -20718,7 +21306,7 @@ 1 2 - 4039 + 4108 @@ -20734,7 +21322,7 @@ 1 2 - 4039 + 4108 @@ -20750,7 +21338,7 @@ 1 2 - 4039 + 4108 @@ -20766,7 +21354,7 @@ 1 2 - 4039 + 4108 @@ -20782,7 +21370,7 @@ 1 2 - 4039 + 4108 @@ -20798,7 +21386,7 @@ 1 2 - 4039 + 4108 @@ -20808,11 +21396,11 @@ symbol_array_child - 667 + 687 symbol_array - 136 + 139 index @@ -20820,7 +21408,7 @@ child - 667 + 687 @@ -20839,37 +21427,37 @@ 2 3 - 24 + 25 3 4 - 12 + 13 4 6 - 11 + 8 6 - 8 + 7 + 7 + + + 7 + 10 12 - 8 - 15 + 10 + 16 12 - 15 - 22 - 10 - - - 24 + 16 33 - 3 + 10 @@ -20890,37 +21478,37 @@ 2 3 - 24 + 25 3 4 - 12 + 13 4 6 - 11 + 8 6 - 8 + 7 + 7 + + + 7 + 10 12 - 8 - 15 + 10 + 16 12 - 15 - 22 - 10 - - - 24 + 16 33 - 3 + 10 @@ -20936,12 +21524,12 @@ 1 2 - 6 + 5 2 3 - 2 + 3 3 @@ -20979,28 +21567,28 @@ 2 - 23 - 26 + 25 + 29 2 - 31 - 38 + 34 + 42 2 - 41 - 49 + 42 + 50 2 - 60 - 85 + 62 + 88 2 - 133 - 134 + 136 + 137 1 @@ -21017,12 +21605,12 @@ 1 2 - 6 + 5 2 3 - 2 + 3 3 @@ -21060,28 +21648,28 @@ 2 - 23 - 26 + 25 + 29 2 - 31 - 38 + 34 + 42 2 - 41 - 49 + 42 + 50 2 - 60 - 85 + 62 + 88 2 - 133 - 134 + 136 + 137 1 @@ -21098,7 +21686,7 @@ 1 2 - 667 + 687 @@ -21114,7 +21702,7 @@ 1 2 - 667 + 687 @@ -21124,15 +21712,15 @@ symbol_array_def - 136 + 139 id - 136 + 139 loc - 136 + 139 @@ -21146,7 +21734,7 @@ 1 2 - 136 + 139 @@ -21162,7 +21750,7 @@ 1 2 - 136 + 139 @@ -21172,19 +21760,19 @@ then_child - 12723 + 12972 then - 7463 + 7609 index - 29 + 35 child - 12723 + 12972 @@ -21198,22 +21786,22 @@ 1 2 - 4617 + 4705 2 3 - 1691 + 1734 3 4 - 633 + 641 4 - 30 - 521 + 36 + 528 @@ -21229,22 +21817,22 @@ 1 2 - 4617 + 4705 2 3 - 1691 + 1734 3 4 - 633 + 641 4 - 30 - 521 + 36 + 528 @@ -21260,52 +21848,42 @@ 1 2 - 9 + 14 - 4 + 3 5 - 5 - - - 6 - 8 2 - 8 + 5 + 6 + 4 + + + 7 10 - 2 + 3 - 18 - 25 - 2 + 10 + 26 + 3 - 40 - 60 - 2 + 42 + 86 + 3 - 82 - 153 - 2 + 152 + 517 + 3 - 282 - 508 - 2 - - - 1123 - 2768 - 2 - - - 7256 - 7257 - 1 + 1143 + 7434 + 3 @@ -21321,52 +21899,42 @@ 1 2 - 9 + 14 - 4 + 3 5 - 5 - - - 6 - 8 2 - 8 + 5 + 6 + 4 + + + 7 10 - 2 + 3 - 18 - 25 - 2 + 10 + 26 + 3 - 40 - 60 - 2 + 42 + 86 + 3 - 82 - 153 - 2 + 152 + 517 + 3 - 282 - 508 - 2 - - - 1123 - 2768 - 2 - - - 7256 - 7257 - 1 + 1143 + 7434 + 3 @@ -21382,7 +21950,7 @@ 1 2 - 12723 + 12972 @@ -21398,7 +21966,7 @@ 1 2 - 12723 + 12972 @@ -21408,15 +21976,15 @@ then_def - 7463 + 7609 id - 7463 + 7609 loc - 7463 + 7609 @@ -21430,7 +21998,7 @@ 1 2 - 7463 + 7609 @@ -21446,7 +22014,7 @@ 1 2 - 7463 + 7609 @@ -21456,11 +22024,11 @@ tokeninfo - 1779691 + 1812992 id - 1779691 + 1812992 kind @@ -21468,19 +22036,19 @@ file - 3617 + 3633 idx - 29716 + 30516 value - 80134 + 81342 loc - 1779666 + 1812967 @@ -21494,7 +22062,7 @@ 1 2 - 1779691 + 1812992 @@ -21510,7 +22078,7 @@ 1 2 - 1779691 + 1812992 @@ -21526,7 +22094,7 @@ 1 2 - 1779691 + 1812992 @@ -21542,7 +22110,7 @@ 1 2 - 1779691 + 1812992 @@ -21558,7 +22126,7 @@ 1 2 - 1779691 + 1812992 @@ -21577,58 +22145,58 @@ 2 - 103 - 180 + 106 + 182 2 - 418 - 1479 + 431 + 1506 2 - 1524 - 1525 + 1573 + 1574 2 - 3450 - 3546 + 3578 + 3605 2 - 3626 - 4930 + 3720 + 5057 2 - 6964 - 8063 + 7139 + 8328 2 - 12486 - 15157 + 12622 + 15383 2 - 21161 - 48149 + 21595 + 49328 2 - 48764 - 69135 + 49585 + 70852 2 - 80850 - 434806 + 82879 + 445442 2 - 963804 - 963805 + 986482 + 986483 1 @@ -21649,7 +22217,7 @@ 24 - 78 + 81 2 @@ -21658,48 +22226,48 @@ 1 - 432 - 433 + 448 + 449 3 - 475 + 486 502 2 - 789 - 892 + 794 + 904 2 - 1238 - 1287 + 1254 + 1305 2 - 1326 - 1588 + 1347 + 1610 2 - 2257 - 2344 + 2282 + 2363 2 - 2854 - 3364 + 2879 + 3394 2 - 3467 - 3499 + 3498 + 3531 2 - 3506 - 3507 + 3538 + 3539 1 @@ -21719,58 +22287,58 @@ 2 - 96 - 140 + 99 + 136 2 - 316 - 412 + 331 + 422 2 - 997 - 1006 + 1015 + 1027 2 - 1756 - 2025 + 1775 + 2075 2 - 2088 - 2291 + 2128 + 2308 2 - 3284 - 3338 + 3338 + 3381 2 - 3399 - 4077 + 3467 + 4192 2 - 6434 - 8419 + 6552 + 8526 2 - 9553 - 9760 + 9771 + 9941 2 - 11689 - 21405 + 11957 + 21770 2 - 25900 - 25901 + 26505 + 26506 1 @@ -21795,13 +22363,13 @@ 2 - 43 - 48 + 42 + 50 2 - 53 - 54 + 52 + 53 1 @@ -21811,27 +22379,27 @@ 136 - 506 + 510 2 - 1601 - 2567 + 1614 + 2649 2 - 3332 - 4106 + 3380 + 4151 2 - 6907 - 8754 + 7019 + 8929 2 - 16792 - 37826 + 17094 + 38702 2 @@ -21851,58 +22419,58 @@ 2 - 103 - 180 + 106 + 182 2 - 418 - 1479 + 431 + 1506 2 - 1524 - 1525 + 1573 + 1574 2 - 3450 - 3546 + 3578 + 3605 2 - 3626 - 4930 + 3720 + 5057 2 - 6964 - 8063 + 7139 + 8328 2 - 12486 - 15157 + 12622 + 15383 2 - 21161 - 48149 + 21595 + 49328 2 - 48764 - 69135 + 49585 + 70852 2 - 80850 - 434806 + 82879 + 445442 2 - 963804 - 963805 + 986482 + 986483 1 @@ -21919,67 +22487,67 @@ 1 21 - 325 + 327 21 28 - 293 + 294 28 34 - 293 + 294 34 47 - 275 + 279 47 63 - 278 + 277 63 85 - 276 + 277 85 - 127 + 128 275 - 127 - 188 + 128 + 190 273 - 188 - 284 + 190 + 287 274 - 284 - 470 - 271 + 287 + 477 + 273 - 470 - 807 - 271 + 477 + 824 + 273 - 810 - 1764 - 271 + 830 + 1793 + 273 - 1766 - 28890 - 236 + 1795 + 29810 + 238 @@ -21995,47 +22563,47 @@ 1 6 - 303 + 300 6 7 - 603 + 600 7 8 - 339 + 340 8 9 - 558 + 560 9 10 - 549 + 552 10 11 - 391 + 387 11 12 - 292 + 304 12 14 - 325 + 327 14 22 - 254 + 256 @@ -22051,67 +22619,67 @@ 1 21 - 325 + 327 21 28 - 293 + 294 28 34 - 293 + 294 34 47 - 275 + 279 47 63 - 278 + 277 63 85 - 276 + 277 85 - 127 + 128 275 - 127 - 188 + 128 + 190 273 - 188 - 284 + 190 + 287 274 - 284 - 470 - 271 + 287 + 477 + 273 - 470 - 807 - 271 + 477 + 824 + 273 - 810 - 1764 - 271 + 830 + 1793 + 273 - 1766 - 28890 - 236 + 1795 + 29810 + 238 @@ -22127,67 +22695,67 @@ 1 18 - 256 + 259 18 21 - 320 + 318 21 24 - 304 + 309 24 29 - 319 + 322 29 35 - 301 + 303 35 42 - 301 + 294 42 53 - 291 + 287 53 67 - 281 + 284 67 86 - 280 + 279 86 - 120 - 271 + 121 + 277 - 120 + 121 175 - 272 + 274 175 - 331 - 272 + 328 + 273 - 333 - 1569 - 142 + 328 + 1615 + 149 @@ -22203,67 +22771,67 @@ 1 21 - 325 + 327 21 28 - 293 + 294 28 34 - 293 + 294 34 47 - 275 + 279 47 63 - 278 + 277 63 85 - 276 + 277 85 - 127 + 128 275 - 127 - 188 + 128 + 190 273 - 188 - 284 + 190 + 287 274 - 284 - 470 - 271 + 287 + 477 + 273 - 470 - 807 - 271 + 477 + 824 + 273 - 810 - 1764 - 271 + 830 + 1793 + 273 - 1766 - 28890 - 236 + 1795 + 29810 + 238 @@ -22279,57 +22847,57 @@ 1 2 - 5667 + 6221 2 3 - 322 + 281 3 4 - 5904 + 6071 4 5 - 2235 + 2334 5 - 7 - 2545 + 8 + 2773 - 7 - 10 - 2643 + 8 + 11 + 2410 - 10 + 11 22 - 2328 + 2394 22 - 39 - 2288 + 42 + 2451 - 39 - 93 - 2247 + 42 + 108 + 2292 - 93 - 339 - 2230 + 108 + 438 + 2289 - 339 - 3518 - 1301 + 439 + 3550 + 996 @@ -22345,37 +22913,37 @@ 1 2 - 7302 + 7969 2 3 - 6501 + 6564 3 4 - 4777 + 4657 4 5 - 2476 + 2483 5 6 - 1597 + 1748 6 8 - 2343 + 2280 8 12 - 2668 + 2760 12 @@ -22396,57 +22964,57 @@ 1 2 - 5667 + 6221 2 3 - 322 + 281 3 4 - 5904 + 6071 4 5 - 2235 + 2334 5 - 7 - 2545 + 8 + 2773 - 7 - 10 - 2643 + 8 + 11 + 2410 - 10 + 11 22 - 2328 + 2394 22 - 39 - 2288 + 42 + 2451 - 39 - 93 - 2247 + 42 + 108 + 2292 - 93 - 339 - 2230 + 108 + 438 + 2289 - 339 - 3518 - 1301 + 439 + 3550 + 996 @@ -22462,57 +23030,57 @@ 1 2 - 5696 + 6252 2 3 - 937 + 904 3 4 - 5749 + 5907 4 5 - 2001 + 2078 5 7 - 2701 + 2404 7 10 - 2382 + 2623 10 18 - 2494 + 2586 18 - 29 - 2266 + 31 + 2381 - 29 - 61 - 2261 + 31 + 65 + 2313 - 61 - 177 - 2234 + 65 + 215 + 2293 - 177 - 1940 - 991 + 215 + 1962 + 768 @@ -22528,57 +23096,57 @@ 1 2 - 5667 + 6221 2 3 - 322 + 281 3 4 - 5904 + 6071 4 5 - 2235 + 2334 5 - 7 - 2545 + 8 + 2773 - 7 - 10 - 2643 + 8 + 11 + 2410 - 10 + 11 22 - 2328 + 2394 22 - 39 - 2288 + 42 + 2451 - 39 - 93 - 2247 + 42 + 108 + 2292 - 93 - 339 - 2230 + 108 + 438 + 2289 - 339 - 3518 - 1301 + 439 + 3550 + 996 @@ -22594,32 +23162,32 @@ 1 2 - 47187 + 47906 2 3 - 11705 + 11908 3 4 - 5685 + 5748 4 7 - 6732 + 6839 7 25 - 6082 + 6164 25 - 159758 - 2740 + 163812 + 2775 @@ -22635,12 +23203,12 @@ 1 2 - 76002 + 77153 2 5 - 4132 + 4189 @@ -22656,22 +23224,22 @@ 1 2 - 61368 + 62308 2 3 - 8004 + 8151 3 6 - 6135 + 6181 6 - 3415 - 4624 + 3447 + 4700 @@ -22687,32 +23255,32 @@ 1 2 - 47307 + 48028 2 3 - 11704 + 11906 3 4 - 5685 + 5746 4 7 - 6712 + 6815 7 25 - 6057 + 6150 25 - 15421 - 2666 + 15624 + 2694 @@ -22728,32 +23296,32 @@ 1 2 - 47188 + 47907 2 3 - 11704 + 11907 3 4 - 5685 + 5748 4 7 - 6732 + 6839 7 25 - 6083 + 6165 25 - 159758 - 2739 + 163812 + 2774 @@ -22769,7 +23337,7 @@ 1 2 - 1779641 + 1812942 2 @@ -22790,7 +23358,7 @@ 1 2 - 1779641 + 1812942 2 @@ -22811,7 +23379,7 @@ 1 2 - 1779666 + 1812967 @@ -22827,7 +23395,7 @@ 1 2 - 1779641 + 1812942 2 @@ -22848,7 +23416,7 @@ 1 2 - 1779666 + 1812967 @@ -22858,15 +23426,15 @@ unary_def - 2390 + 2445 id - 2390 + 2445 operand - 2390 + 2445 operator @@ -22874,7 +23442,7 @@ loc - 2390 + 2445 @@ -22888,7 +23456,7 @@ 1 2 - 2390 + 2445 @@ -22904,7 +23472,7 @@ 1 2 - 2390 + 2445 @@ -22920,7 +23488,7 @@ 1 2 - 2390 + 2445 @@ -22936,7 +23504,7 @@ 1 2 - 2390 + 2445 @@ -22952,7 +23520,7 @@ 1 2 - 2390 + 2445 @@ -22968,7 +23536,7 @@ 1 2 - 2390 + 2445 @@ -22997,13 +23565,13 @@ 1 - 525 - 526 + 533 + 534 1 - 1587 - 1588 + 1644 + 1645 1 @@ -23033,13 +23601,13 @@ 1 - 525 - 526 + 533 + 534 1 - 1587 - 1588 + 1644 + 1645 1 @@ -23069,13 +23637,13 @@ 1 - 525 - 526 + 533 + 534 1 - 1587 - 1588 + 1644 + 1645 1 @@ -23092,7 +23660,7 @@ 1 2 - 2390 + 2445 @@ -23108,7 +23676,7 @@ 1 2 - 2390 + 2445 @@ -23124,7 +23692,7 @@ 1 2 - 2390 + 2445 @@ -23346,15 +23914,15 @@ unless_consequence - 481 + 494 unless - 481 + 494 consequence - 481 + 494 @@ -23368,7 +23936,7 @@ 1 2 - 481 + 494 @@ -23384,7 +23952,7 @@ 1 2 - 481 + 494 @@ -23394,19 +23962,19 @@ unless_def - 481 + 497 id - 481 + 497 condition - 481 + 497 loc - 481 + 497 @@ -23420,7 +23988,7 @@ 1 2 - 481 + 497 @@ -23436,7 +24004,7 @@ 1 2 - 481 + 497 @@ -23452,7 +24020,7 @@ 1 2 - 481 + 497 @@ -23468,7 +24036,7 @@ 1 2 - 481 + 497 @@ -23484,7 +24052,7 @@ 1 2 - 481 + 497 @@ -23500,7 +24068,7 @@ 1 2 - 481 + 497 @@ -23510,23 +24078,23 @@ unless_modifier_def - 1396 + 1404 id - 1396 + 1404 body - 1396 + 1404 condition - 1396 + 1404 loc - 1396 + 1404 @@ -23540,7 +24108,7 @@ 1 2 - 1396 + 1404 @@ -23556,7 +24124,7 @@ 1 2 - 1396 + 1404 @@ -23572,7 +24140,7 @@ 1 2 - 1396 + 1404 @@ -23588,7 +24156,7 @@ 1 2 - 1396 + 1404 @@ -23604,7 +24172,7 @@ 1 2 - 1396 + 1404 @@ -23620,7 +24188,7 @@ 1 2 - 1396 + 1404 @@ -23636,7 +24204,7 @@ 1 2 - 1396 + 1404 @@ -23652,7 +24220,7 @@ 1 2 - 1396 + 1404 @@ -23668,7 +24236,7 @@ 1 2 - 1396 + 1404 @@ -23684,7 +24252,7 @@ 1 2 - 1396 + 1404 @@ -23700,7 +24268,7 @@ 1 2 - 1396 + 1404 @@ -23716,7 +24284,7 @@ 1 2 - 1396 + 1404 @@ -23726,23 +24294,23 @@ until_def - 14 + 16 id - 14 + 16 body - 14 + 16 condition - 14 + 16 loc - 14 + 16 @@ -23756,7 +24324,7 @@ 1 2 - 14 + 16 @@ -23772,7 +24340,7 @@ 1 2 - 14 + 16 @@ -23788,7 +24356,7 @@ 1 2 - 14 + 16 @@ -23804,7 +24372,7 @@ 1 2 - 14 + 16 @@ -23820,7 +24388,7 @@ 1 2 - 14 + 16 @@ -23836,7 +24404,7 @@ 1 2 - 14 + 16 @@ -23852,7 +24420,7 @@ 1 2 - 14 + 16 @@ -23868,7 +24436,7 @@ 1 2 - 14 + 16 @@ -23884,7 +24452,7 @@ 1 2 - 14 + 16 @@ -23900,7 +24468,7 @@ 1 2 - 14 + 16 @@ -23916,7 +24484,7 @@ 1 2 - 14 + 16 @@ -23932,7 +24500,7 @@ 1 2 - 14 + 16 @@ -24158,15 +24726,15 @@ when_body - 963 + 980 when - 963 + 980 body - 963 + 980 @@ -24180,7 +24748,7 @@ 1 2 - 963 + 980 @@ -24196,7 +24764,7 @@ 1 2 - 963 + 980 @@ -24206,15 +24774,15 @@ when_def - 970 + 987 id - 970 + 987 loc - 970 + 987 @@ -24228,7 +24796,7 @@ 1 2 - 970 + 987 @@ -24244,7 +24812,7 @@ 1 2 - 970 + 987 @@ -24254,11 +24822,11 @@ when_pattern - 1171 + 1186 when - 970 + 987 index @@ -24266,7 +24834,7 @@ pattern - 1171 + 1186 @@ -24280,12 +24848,12 @@ 1 2 - 844 + 863 2 3 - 96 + 94 3 @@ -24306,12 +24874,12 @@ 1 2 - 844 + 863 2 3 - 96 + 94 3 @@ -24360,13 +24928,13 @@ 1 - 126 - 127 + 124 + 125 1 - 970 - 971 + 987 + 988 1 @@ -24411,13 +24979,13 @@ 1 - 126 - 127 + 124 + 125 1 - 970 - 971 + 987 + 988 1 @@ -24434,7 +25002,7 @@ 1 2 - 1171 + 1186 @@ -24450,7 +25018,7 @@ 1 2 - 1171 + 1186 @@ -24460,23 +25028,23 @@ while_def - 104 + 106 id - 104 + 106 body - 104 + 106 condition - 104 + 106 loc - 104 + 106 @@ -24490,7 +25058,7 @@ 1 2 - 104 + 106 @@ -24506,7 +25074,7 @@ 1 2 - 104 + 106 @@ -24522,7 +25090,7 @@ 1 2 - 104 + 106 @@ -24538,7 +25106,7 @@ 1 2 - 104 + 106 @@ -24554,7 +25122,7 @@ 1 2 - 104 + 106 @@ -24570,7 +25138,7 @@ 1 2 - 104 + 106 @@ -24586,7 +25154,7 @@ 1 2 - 104 + 106 @@ -24602,7 +25170,7 @@ 1 2 - 104 + 106 @@ -24618,7 +25186,7 @@ 1 2 - 104 + 106 @@ -24634,7 +25202,7 @@ 1 2 - 104 + 106 @@ -24650,7 +25218,7 @@ 1 2 - 104 + 106 @@ -24666,7 +25234,7 @@ 1 2 - 104 + 106 @@ -24676,23 +25244,23 @@ while_modifier_def - 8 + 9 id - 8 + 9 body - 8 + 9 condition - 8 + 9 loc - 8 + 9 @@ -24706,7 +25274,7 @@ 1 2 - 8 + 9 @@ -24722,7 +25290,7 @@ 1 2 - 8 + 9 @@ -24738,7 +25306,7 @@ 1 2 - 8 + 9 @@ -24754,7 +25322,7 @@ 1 2 - 8 + 9 @@ -24770,7 +25338,7 @@ 1 2 - 8 + 9 @@ -24786,7 +25354,7 @@ 1 2 - 8 + 9 @@ -24802,7 +25370,7 @@ 1 2 - 8 + 9 @@ -24818,7 +25386,7 @@ 1 2 - 8 + 9 @@ -24834,7 +25402,7 @@ 1 2 - 8 + 9 @@ -24850,7 +25418,7 @@ 1 2 - 8 + 9 @@ -24866,7 +25434,7 @@ 1 2 - 8 + 9 @@ -24882,7 +25450,7 @@ 1 2 - 8 + 9 @@ -24892,15 +25460,15 @@ yield_child - 367 + 371 yield - 367 + 371 child - 367 + 371 @@ -24914,7 +25482,7 @@ 1 2 - 367 + 371 @@ -24930,7 +25498,7 @@ 1 2 - 367 + 371 @@ -24940,15 +25508,15 @@ yield_def - 836 + 841 id - 836 + 841 loc - 836 + 841 @@ -24962,7 +25530,7 @@ 1 2 - 836 + 841 @@ -24978,7 +25546,7 @@ 1 2 - 836 + 841 From 498e760b2115a72b8cc988b8e448ace6b0cf4d55 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Tue, 27 Apr 2021 20:55:53 +0200 Subject: [PATCH 58/66] Add consistency queries to codeqlmanifest --- .codeqlmanifest.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.codeqlmanifest.json b/.codeqlmanifest.json index 6e6333c430c..63200dbfc95 100644 --- a/.codeqlmanifest.json +++ b/.codeqlmanifest.json @@ -1,9 +1,10 @@ { "provide": [ "ql/src/qlpack.yml", + "ql/consistency-queries/qlpack.yml", "ql/test/qlpack.yml", "ql/examples/qlpack.yml", "upgrades/qlpack.yml", "extractor-pack/codeql-extractor.yml" ] -} \ No newline at end of file +} From 3547980f5bca25ba5990d604ea062c83d4ca487f Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Thu, 13 May 2021 15:24:02 +0200 Subject: [PATCH 59/66] Update reference to tree-sitter-embedded-template --- Cargo.lock | 2 +- extractor/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20e44a76f26..3cf8082d015 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -590,7 +590,7 @@ dependencies = [ [[package]] name = "tree-sitter-embedded-template" version = "0.17.0" -source = "git+https://github.com/aibaars/tree-sitter-embedded-template?rev=d4aac29c08aa7c596633d00b5ec2dd2d247eafe4#d4aac29c08aa7c596633d00b5ec2dd2d247eafe4" +source = "git+https://github.com/tree-sitter/tree-sitter-embedded-template?rev=d4aac29c08aa7c596633d00b5ec2dd2d247eafe4#d4aac29c08aa7c596633d00b5ec2dd2d247eafe4" dependencies = [ "cc", "tree-sitter", diff --git a/extractor/Cargo.toml b/extractor/Cargo.toml index ebe82e28282..cc600391701 100644 --- a/extractor/Cargo.toml +++ b/extractor/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" flate2 = "1.0" node-types = { path = "../node-types" } tree-sitter = "0.17" -tree-sitter-embedded-template = { git = "https://github.com/aibaars/tree-sitter-embedded-template", rev = "d4aac29c08aa7c596633d00b5ec2dd2d247eafe4" } +tree-sitter-embedded-template = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template", rev = "d4aac29c08aa7c596633d00b5ec2dd2d247eafe4" } tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "32cd5a04adb4accb0c121f037ab59df3c3488228" } clap = "2.33" tracing = "0.1" From 66bf13e77a1b2951a4ccf3190527c04c44087229 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Tue, 27 Apr 2021 11:46:11 +0000 Subject: [PATCH 60/66] Setup a CodeSpace --- .devcontainer/Dockerfile | 15 +++++++++++++ .devcontainer/devcontainer.json | 39 +++++++++++++++++++++++++++++++++ .devcontainer/post_attach.sh | 37 +++++++++++++++++++++++++++++++ .devcontainer/post_create.sh | 4 ++++ 4 files changed, 95 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100755 .devcontainer/post_attach.sh create mode 100755 .devcontainer/post_create.sh diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000000..a5776e19806 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,15 @@ +# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/rust/.devcontainer/base.Dockerfile + +FROM mcr.microsoft.com/vscode/devcontainers/rust:0-1 + +RUN apt-key --keyring /usr/share/keyrings/githubcli-archive-keyring.gpg adv \ + --keyserver keyserver.ubuntu.com --recv-key C99B11DEB97541F0 && \ + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages $(lsb_release -cs) main" \ + | tee /etc/apt/sources.list.d/github-cli2.list > /dev/null + + +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends gh + +COPY post_create.sh /bin/post_create.sh +COPY post_attach.sh /bin/post_attach.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..b7824f45cfe --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,39 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/rust +{ + "name": "Rust", + "build": { + "dockerfile": "Dockerfile" + }, + "runArgs": [ + "--cap-add=SYS_PTRACE", + "--security-opt", + "seccomp=unconfined" + ], + // Set *default* container specific settings.json values on container create. + "settings": { + "terminal.integrated.shell.linux": "/bin/bash", + "lldb.executable": "/usr/bin/lldb", + // VS Code don't watch files under ./target + "files.watcherExclude": { + "**/target/**": true + } + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "rust-lang.rust", + "bungcip.better-toml", + "vadimcn.vscode-lldb", + "mutantdino.resourcemonitor", + "ms-azuretools.vscode-docker", + "github.vscode-codeql" + ], + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "rustc --version", + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode", + "postCreateCommand": [ "/bin/post_create.sh" ], + "postAttachCommand": [ "flock", "-E", "0", "-n", "/var/lock/post_attach.lock", "/bin/post_attach.sh" ] +} \ No newline at end of file diff --git a/.devcontainer/post_attach.sh b/.devcontainer/post_attach.sh new file mode 100755 index 00000000000..989ed912be9 --- /dev/null +++ b/.devcontainer/post_attach.sh @@ -0,0 +1,37 @@ +#! /bin/bash +set -xe + +echo "Check installed CodeQL version" +CURRENT_CODEQL_BIN=$(readlink -e /usr/local/bin/codeql || echo "") +LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | tail -1) + +BASE_DIR=/home/vscode/codeql-binaries +mkdir -p "${BASE_DIR}" +LATEST_CODEQL_DIR="${BASE_DIR}/codeql-${LATEST}" +LATEST_CODEQL_BIN="${LATEST_CODEQL_DIR}/codeql/codeql" + +if [ "${CURRENT_CODEQL_BIN}" != "${LATEST_CODEQL_BIN}" ]; then + echo "Installing CodeQL ${LATEST}" + TMPDIR=$(mktemp -d -p "$(dirname ${LATEST_CODEQL_DIR})") + gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip -D "${TMPDIR}" "$LATEST" + unzip -oq "${TMPDIR}/codeql-linux64.zip" -d "${TMPDIR}" + rm -f "${TMPDIR}/codeql-linux64.zip" + mv "${TMPDIR}" "${LATEST_CODEQL_DIR}" + test -x "${LATEST_CODEQL_BIN}" && sudo ln -sf "${LATEST_CODEQL_BIN}" /usr/local/bin/codeql + if [[ "${CURRENT_CODEQL_BIN}" =~ .*/codeql/codeql ]]; then + rm -rf "$(dirname $(dirname ${CURRENT_CODEQL_BIN}))" + fi +fi + +echo "Build the Ruby extractor" + +# clone the git dependencies using "git clone" because cargo's builtin git support is rather slow +REPO_DIR="${CARGO_HOME:-/home/vscode/.cargo}/git/db" +REPO_DIR_ERB="${REPO_DIR}/tree-sitter-embedded-template-4c796e3340c233b6" +REPO_DIR_RUBY="${REPO_DIR}/tree-sitter-ruby-666a40ce046f8e7a" + +mkdir -p "${REPO_DIR}" +test -e "${REPO_DIR_ERB}" || git clone -q --bare https://github.com/tree-sitter/tree-sitter-embedded-template "${REPO_DIR_ERB}" +test -e "${REPO_DIR_RUBY}" || git clone -q --bare https://github.com/tree-sitter/tree-sitter-ruby.git "${REPO_DIR_RUBY}" + +./create-extractor-pack.sh diff --git a/.devcontainer/post_create.sh b/.devcontainer/post_create.sh new file mode 100755 index 00000000000..a1af653024b --- /dev/null +++ b/.devcontainer/post_create.sh @@ -0,0 +1,4 @@ +#! /bin/bash + +mkdir -p /home/vscode/.config/codeql +echo '--search-path /workspaces/codeql-ruby' >> /home/vscode/.config/codeql/config From 7ff2ca4ffe083d31916d95cf9f84ce68bffe2701 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 14 May 2021 15:56:59 +0100 Subject: [PATCH 61/66] improve rb/summary/lines-of-user-code name and description --- ql/src/queries/summary/LinesOfUserCode.ql | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ql/src/queries/summary/LinesOfUserCode.ql b/ql/src/queries/summary/LinesOfUserCode.ql index c7dbb7ee5ba..7f12e3e5a5b 100644 --- a/ql/src/queries/summary/LinesOfUserCode.ql +++ b/ql/src/queries/summary/LinesOfUserCode.ql @@ -1,7 +1,9 @@ /** * @id rb/summary/lines-of-user-code - * @name Lines of authored Ruby code in the database - * @description The total number of lines of Ruby code across files, excluding library and generated code. + * @name Total Lines of user written Ruby code in the database + * @description The total number of lines of Ruby code from the source code + * directory, excluding external library and auto-generated files. This + * query counts the lines of code, excluding whitespace or comments. * @kind metric * @tags summary */ From 71234155b897d738b736a8870a7d153228b718a0 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 14 May 2021 15:59:07 +0100 Subject: [PATCH 62/66] improve rb/summary/lines-of-code description --- ql/src/queries/summary/LinesOfCode.ql | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ql/src/queries/summary/LinesOfCode.ql b/ql/src/queries/summary/LinesOfCode.ql index 958a931a16d..1f2570d06d1 100644 --- a/ql/src/queries/summary/LinesOfCode.ql +++ b/ql/src/queries/summary/LinesOfCode.ql @@ -1,9 +1,10 @@ /** * @id rb/summary/lines-of-code * @name Total lines of Ruby code in the database - * @description The total number of lines of Ruby code across all files, - * including vendored code, tests. This query counts the lines of code, - * excluding whitespace or comments. + * @description The total number of lines of Ruby code from the source code + * directory, including external libraries and auto-generated files. This is a + * useful metric of the size of a database. This query counts the lines of + * code, excluding whitespace or comments. * @kind metric * @tags summary */ From 65b0ce204d2c3c7f73972cf7920c9833a2399906 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 14 May 2021 15:59:48 +0100 Subject: [PATCH 63/66] restrict rb/summary/lines-of-code to the source root --- ql/src/queries/summary/LinesOfCode.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/src/queries/summary/LinesOfCode.ql b/ql/src/queries/summary/LinesOfCode.ql index 1f2570d06d1..2b2980d8e17 100644 --- a/ql/src/queries/summary/LinesOfCode.ql +++ b/ql/src/queries/summary/LinesOfCode.ql @@ -11,4 +11,4 @@ import ruby -select sum(File f | | f.getNumberOfLinesOfCode()) +select sum(File f | exists(f.getRelativePath()) | f.getNumberOfLinesOfCode()) From 1ba491a956b32e82da9f33b18b230cae228ec792 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 14 May 2021 17:06:49 +0100 Subject: [PATCH 64/66] add lines-of-code tag to rb/summary/lines-of-code --- ql/src/queries/summary/LinesOfCode.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/ql/src/queries/summary/LinesOfCode.ql b/ql/src/queries/summary/LinesOfCode.ql index 2b2980d8e17..32590b861af 100644 --- a/ql/src/queries/summary/LinesOfCode.ql +++ b/ql/src/queries/summary/LinesOfCode.ql @@ -7,6 +7,7 @@ * code, excluding whitespace or comments. * @kind metric * @tags summary + * lines-of-code */ import ruby From b434d42d05d57bc3f63e3cd0fcdfc06d8728aca2 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 17 May 2021 13:39:44 +0200 Subject: [PATCH 65/66] Rename `ParenthesizedExprSynth` to `StmtSequenceSynth` --- ql/src/codeql_ruby/ast/Expr.qll | 24 +++++++++---------- ql/src/codeql_ruby/ast/internal/AST.qll | 18 ++++++-------- ql/src/codeql_ruby/ast/internal/Synthesis.qll | 2 +- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/ql/src/codeql_ruby/ast/Expr.qll b/ql/src/codeql_ruby/ast/Expr.qll index 17b52b97268..2eccc897ed7 100644 --- a/ql/src/codeql_ruby/ast/Expr.qll +++ b/ql/src/codeql_ruby/ast/Expr.qll @@ -79,6 +79,12 @@ class StmtSequence extends Expr, TStmtSequence { override AstNode getAChild(string pred) { pred = "getStmt" and result = this.getStmt(_) } } +private class StmtSequenceSynth extends StmtSequence, TStmtSequenceSynth { + final override Stmt getStmt(int n) { synthChild(this, n, result) } + + final override string toString() { result = "..." } +} + private class Then extends StmtSequence, TThen { private Generated::Then g; @@ -206,23 +212,17 @@ class BodyStmt extends StmtSequence, TBodyStmt { * ``` */ class ParenthesizedExpr extends StmtSequence, TParenthesizedExpr { + private Generated::ParenthesizedStatements g; + + ParenthesizedExpr() { this = TParenthesizedExpr(g) } + + final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } + final override string getAPrimaryQlClass() { result = "ParenthesizedExpr" } final override string toString() { result = "( ... )" } } -private class ParenthesizedExprReal extends ParenthesizedExpr, TParenthesizedExprReal { - private Generated::ParenthesizedStatements g; - - ParenthesizedExprReal() { this = TParenthesizedExprReal(g) } - - final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } -} - -private class ParenthesizedExprSynth extends ParenthesizedExpr, TParenthesizedExprSynth { - final override Stmt getStmt(int n) { synthChild(this, n, result) } -} - /** * A pair expression. For example, in a hash: * ```rb diff --git a/ql/src/codeql_ruby/ast/internal/AST.qll b/ql/src/codeql_ruby/ast/internal/AST.qll index 9dd3c35058e..7af573dad0d 100644 --- a/ql/src/codeql_ruby/ast/internal/AST.qll +++ b/ql/src/codeql_ruby/ast/internal/AST.qll @@ -188,10 +188,7 @@ private module Cached { TNotExpr(Generated::Unary g) { g instanceof @unary_bang or g instanceof @unary_not } or TOptionalParameter(Generated::OptionalParameter g) or TPair(Generated::Pair g) or - TParenthesizedExprReal(Generated::ParenthesizedStatements g) or - TParenthesizedExprSynth(AST::AstNode parent, int i) { - mkSynthChild(ParenthesizedExprKind(), parent, i) - } or + TParenthesizedExpr(Generated::ParenthesizedStatements g) or TRShiftExprReal(Generated::Binary g) { g instanceof @binary_ranglerangle } or TRShiftExprSynth(AST::AstNode parent, int i) { mkSynthChild(RShiftExprKind(), parent, i) } or TRangeLiteral(Generated::Range g) or @@ -231,6 +228,7 @@ private module Cached { TSpaceshipExpr(Generated::Binary g) { g instanceof @binary_langleequalrangle } or TSplatArgument(Generated::SplatArgument g) or TSplatParameter(Generated::SplatParameter g) or + TStmtSequenceSynth(AST::AstNode parent, int i) { mkSynthChild(StmtSequenceKind(), parent, i) } or TStringArrayLiteral(Generated::StringArray g) or TStringConcatenation(Generated::ChainedString g) or TStringEscapeSequenceComponent(Generated::EscapeSequence g) or @@ -369,7 +367,7 @@ private module Cached { n = TNotExpr(result) or n = TOptionalParameter(result) or n = TPair(result) or - n = TParenthesizedExprReal(result) or + n = TParenthesizedExpr(result) or n = TRShiftExprReal(result) or n = TRangeLiteral(result) or n = TRationalLiteral(result) or @@ -484,15 +482,15 @@ private module Cached { kind = MulExprKind() and result = TMulExprSynth(parent, i) or - kind = ParenthesizedExprKind() and - result = TParenthesizedExprSynth(parent, i) - or kind = RShiftExprKind() and result = TRShiftExprSynth(parent, i) or kind = SelfKind() and result = TSelfSynth(parent, i) or + kind = StmtSequenceKind() and + result = TStmtSequenceSynth(parent, i) + or kind = SubExprKind() and result = TSubExprSynth(parent, i) ) @@ -560,9 +558,7 @@ class TExpr = class TStmtSequence = TBeginBlock or TEndBlock or TThen or TElse or TDo or TEnsure or TStringInterpolationComponent or - TBlock or TBodyStmt or TParenthesizedExpr; - -class TParenthesizedExpr = TParenthesizedExprReal or TParenthesizedExprSynth; + TBlock or TBodyStmt or TParenthesizedExpr or TStmtSequenceSynth; class TBodyStmt = TBeginExpr or TModuleBase or TMethod or TLambda or TDoBlock or TSingletonMethod; diff --git a/ql/src/codeql_ruby/ast/internal/Synthesis.qll b/ql/src/codeql_ruby/ast/internal/Synthesis.qll index 6cdca0db8e8..521bd3d430a 100644 --- a/ql/src/codeql_ruby/ast/internal/Synthesis.qll +++ b/ql/src/codeql_ruby/ast/internal/Synthesis.qll @@ -25,7 +25,7 @@ newtype SynthKind = LogicalOrExprKind() or ModuloExprKind() or MulExprKind() or - ParenthesizedExprKind() or + StmtSequenceKind() or RShiftExprKind() or SelfKind() or SubExprKind() From 25f226e9dcde46757bccdb732318a03f8e353fd0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 17 May 2021 15:02:40 +0200 Subject: [PATCH 66/66] Add comment to `getVariableReal` --- ql/src/codeql_ruby/ast/internal/Variable.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ql/src/codeql_ruby/ast/internal/Variable.qll b/ql/src/codeql_ruby/ast/internal/Variable.qll index 456286f20a2..21becb15cce 100644 --- a/ql/src/codeql_ruby/ast/internal/Variable.qll +++ b/ql/src/codeql_ruby/ast/internal/Variable.qll @@ -508,6 +508,11 @@ class TVariableAccessReal = TClassVariableAccess; abstract class VariableAccessReal extends VariableAccess, TVariableAccessReal { + /** + * Same as `getVariable()`, but restricted to non-synthesized variable accesses. + * + * The sole purpose of this predicate is to make AST synthesis monotonic. + */ abstract VariableReal getVariableReal(); }