diff --git a/ql/src/codeql_ruby/ast/internal/Variable.qll b/ql/src/codeql_ruby/ast/internal/Variable.qll index 43f4918fde3..7177334f62e 100644 --- a/ql/src/codeql_ruby/ast/internal/Variable.qll +++ b/ql/src/codeql_ruby/ast/internal/Variable.qll @@ -5,8 +5,23 @@ private import codeql_ruby.ast.internal.Expr private import codeql_ruby.ast.internal.Method private import codeql_ruby.ast.internal.Pattern -private Generated::AstNode parent(Generated::AstNode n) { - result = n.getParent() and +Generated::AstNode parentOf(Generated::AstNode n) { + exists(Generated::AstNode parent | parent = n.getParent() | + if + n = + [ + parent.(Generated::Module).getName(), parent.(Generated::Class).getName(), + parent.(Generated::Class).getSuperclass(), parent.(Generated::SingletonClass).getValue(), + parent.(Generated::Method).getName(), parent.(Generated::SingletonMethod).getName(), + parent.(Generated::SingletonMethod).getObject() + ] + then result = parent.getParent() + else result = parent + ) +} + +private Generated::AstNode parentOfNoScope(Generated::AstNode n) { + result = parentOf(n) and not n = any(VariableScope s).getScopeElement() } @@ -134,7 +149,7 @@ private module Cached { /** Gets the enclosing scope for `node`. */ cached VariableScope enclosingScope(Generated::AstNode node) { - result.getScopeElement() = parent*(node.getParent()) + result.getScopeElement() = parentOfNoScope*(parentOf(node)) } cached diff --git a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll index 5207043e3c7..91272933774 100644 --- a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll @@ -33,6 +33,7 @@ private import codeql_ruby.ast.internal.TreeSitter::Generated private import AstNodes +private import codeql_ruby.ast.internal.Variable private import codeql_ruby.controlflow.ControlFlowGraph private import Completion private import SuccessorTypes @@ -146,7 +147,7 @@ module CfgScope { } private AstNode parent(AstNode n) { - result.getAFieldOrChild() = n and + result = parentOf(n) and not n instanceof CfgScope } @@ -1262,7 +1263,7 @@ cached private module Cached { /** Gets the CFG scope of node `n`. */ cached - CfgScope getCfgScope(AstNode n) { result = unique(CfgScope scope | scope = parent+(n)) } + CfgScope getCfgScope(AstNode n) { result = unique(CfgScope scope | scope = parent*(parentOf(n))) } private predicate isAbnormalExitType(SuccessorType t) { t instanceof RaiseSuccessor or t instanceof ExitSuccessor diff --git a/ql/test/library-tests/ast/modules/singleton_classes.expected b/ql/test/library-tests/ast/modules/singleton_classes.expected index 9d810846f60..b7b9ab29966 100644 --- a/ql/test/library-tests/ast/modules/singleton_classes.expected +++ b/ql/test/library-tests/ast/modules/singleton_classes.expected @@ -1,5 +1,5 @@ singletonClasses -| classes.rb:41:1:52:3 | class << ... | Class | classes.rb:41:10:41:10 | call to x | +| classes.rb:41:1:52:3 | class << ... | Class | classes.rb:41:10:41:10 | x | exprsInSingletonClasses | classes.rb:41:1:52:3 | class << ... | 0 | classes.rb:42:3:44:5 | length | Method | | classes.rb:41:1:52:3 | class << ... | 1 | classes.rb:46:3:48:5 | wibble | Method | diff --git a/ql/test/library-tests/controlflow/graph/Cfg.expected b/ql/test/library-tests/controlflow/graph/Cfg.expected index 319ae01c0bf..c80f5c8c543 100644 --- a/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -1643,7 +1643,7 @@ cfg.rb: #-----| -> call to print # 148| ... = ... -#-----| -> call to silly +#-----| -> silly # 148| silly #-----| -> ... = ... @@ -1660,7 +1660,7 @@ cfg.rb: # 149| method #-----| -> two_parameters -# 149| call to silly +# 149| silly #-----| -> method # 149| method diff --git a/ql/test/library-tests/variables/scopes.rb b/ql/test/library-tests/variables/scopes.rb index 9f2a97cc0a4..0c5f474ac2a 100644 --- a/ql/test/library-tests/variables/scopes.rb +++ b/ql/test/library-tests/variables/scopes.rb @@ -22,3 +22,19 @@ $global = 42 # use of a pre-defined global variable script = $0 + +class A; end +x = A +module x::B + x = 1 +end +class << x + x = 2 +end +class x::C < x + x = 3 +end +def x.foo + x = 4 +end + diff --git a/ql/test/library-tests/variables/ssa.expected b/ql/test/library-tests/variables/ssa.expected index e58a577689c..a82888cf527 100644 --- a/ql/test/library-tests/variables/ssa.expected +++ b/ql/test/library-tests/variables/ssa.expected @@ -47,6 +47,7 @@ definition | 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 | ... = ... | scopes.rb:13:14:13:14 | d | +| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | | ssa.rb:2:3:2:7 | ... = ... | ssa.rb:2:3:2:3 | i | | ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | @@ -129,6 +130,11 @@ read | 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 | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:14:13:14 | d | scopes.rb:17:9:17:9 | d | +| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:28:8:28:8 | x | +| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:31:10:31:10 | x | +| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:34:7:34:7 | x | +| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:34:14:34:14 | x | +| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:37:5:37:5 | x | | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | ssa.rb:5:6:5:6 | b | | ssa.rb:2:3:2:7 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:3:8:3:8 | i | | ssa.rb:2:3:2:7 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:4:8:4:8 | i | @@ -203,6 +209,7 @@ firstRead | 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 | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:14:13:14 | d | scopes.rb:17:9:17:9 | d | +| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:28:8:28:8 | x | | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | ssa.rb:5:6:5:6 | b | | ssa.rb:2:3:2:7 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:3:8:3:8 | i | | ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:15:8:15:8 | i | @@ -271,6 +278,7 @@ lastRead | 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 | | scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:14:13:14 | d | scopes.rb:17:9:17:9 | d | +| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:37:5:37:5 | x | | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | ssa.rb:5:6:5:6 | b | | ssa.rb:2:3:2:7 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:4:8:4:8 | i | | ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:15:8:15:8 | i | @@ -301,6 +309,10 @@ adjacentReads | 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: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 | +| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:34:14:34:14 | x | scopes.rb:37:5:37:5 | x | | ssa.rb:2:3:2:7 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:3:8:3:8 | i | ssa.rb:4:8:4:8 | i | | 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 | diff --git a/ql/test/library-tests/variables/varaccess.expected b/ql/test/library-tests/variables/varaccess.expected index 568f4aecffd..bee891fa2a7 100644 --- a/ql/test/library-tests/variables/varaccess.expected +++ b/ql/test/library-tests/variables/varaccess.expected @@ -98,23 +98,33 @@ variableAccess | scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x | scopes.rb:2:9:6:3 | block scope | | scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | block scope | | scopes.rb:5:9:5:9 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | block scope | -| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:24:12 | top-level scope | -| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:24:12 | top-level scope | +| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope | +| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope | | scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x | scopes.rb:9:9:18:3 | block scope | -| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:24:12 | top-level scope | -| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:24:12 | top-level scope | -| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:24:12 | top-level scope | -| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:24:12 | top-level scope | +| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope | +| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope | +| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope | +| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope | | scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | block scope | | scopes.rb:13:11:13:11 | c | scopes.rb:13:11:13:11 | c | scopes.rb:9:9:18:3 | block scope | | scopes.rb:13:14:13:14 | d | scopes.rb:13:14:13:14 | d | scopes.rb:9:9:18:3 | block scope | -| scopes.rb:14:9:14:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:24:12 | top-level scope | +| scopes.rb:14:9:14:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope | | scopes.rb:15:9:15:9 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | block scope | | scopes.rb:16:9:16:9 | c | scopes.rb:13:11:13:11 | c | scopes.rb:9:9:18:3 | block scope | | scopes.rb:17:9:17:9 | d | scopes.rb:13:14:13:14 | d | scopes.rb:9:9:18:3 | block scope | | scopes.rb:21:1:21:7 | $global | file://:0:0:0:0 | $global | file://:0:0:0:0 | global scope | -| scopes.rb:24:1:24:6 | script | scopes.rb:24:1:24:6 | script | scopes.rb:1:1:24:12 | top-level scope | +| scopes.rb:24:1:24:6 | script | scopes.rb:24:1:24:6 | script | scopes.rb:1:1:40:1 | top-level scope | | scopes.rb:24:10:24:11 | $0 | file://:0:0:0:0 | $0 | file://:0:0:0:0 | global scope | +| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope | +| scopes.rb:28:8:28:8 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope | +| scopes.rb:29:3:29:3 | x | scopes.rb:29:3:29:3 | x | scopes.rb:28:1:30:3 | module scope | +| scopes.rb:31:10:31:10 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope | +| scopes.rb:32:3:32:3 | x | scopes.rb:32:3:32:3 | x | scopes.rb:31:1:33:3 | class scope | +| scopes.rb:34:7:34:7 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope | +| scopes.rb:34:14:34:14 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope | +| scopes.rb:35:3:35:3 | x | scopes.rb:35:3:35:3 | x | scopes.rb:34:1:36:3 | class scope | +| scopes.rb:37:5:37:5 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope | +| scopes.rb:38:3:38:3 | x | scopes.rb:38:3:38:3 | x | scopes.rb:37:1:39:3 | method scope | | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | ssa.rb:1:1:16:3 | method scope | | ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope | | ssa.rb:3:8:3:8 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope | @@ -190,6 +200,11 @@ explicitWrite | scopes.rb:13:14:13:14 | d | scopes.rb:13:4:13:32 | ... = ... | | scopes.rb:21:1:21:7 | $global | scopes.rb:21:1:21:12 | ... = ... | | scopes.rb:24:1:24:6 | script | scopes.rb:24:1:24:11 | ... = ... | +| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:5 | ... = ... | +| scopes.rb:29:3:29:3 | x | scopes.rb:29:3:29:7 | ... = ... | +| scopes.rb:32:3:32:3 | x | scopes.rb:32:3:32:7 | ... = ... | +| scopes.rb:35:3:35:3 | x | scopes.rb:35:3:35:7 | ... = ... | +| scopes.rb:38:3:38:3 | x | scopes.rb:38:3:38:7 | ... = ... | | ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:7 | ... = ... | | 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 | ... = ... | @@ -310,6 +325,11 @@ readAccess | scopes.rb:16:9:16:9 | c | | scopes.rb:17:9:17:9 | d | | scopes.rb:24:10:24:11 | $0 | +| scopes.rb:28:8:28:8 | x | +| scopes.rb:31:10:31:10 | x | +| scopes.rb:34:7:34:7 | x | +| scopes.rb:34:14:34:14 | x | +| scopes.rb:37:5:37:5 | x | | ssa.rb:3:8:3:8 | i | | ssa.rb:4:8:4:8 | i | | ssa.rb:5:6:5:6 | b | diff --git a/ql/test/library-tests/variables/variable.expected b/ql/test/library-tests/variables/variable.expected index 239e60aacef..e4aefbddc09 100644 --- a/ql/test/library-tests/variables/variable.expected +++ b/ql/test/library-tests/variables/variable.expected @@ -58,6 +58,11 @@ | scopes.rb:13:11:13:11 | c | | scopes.rb:13:14:13:14 | d | | scopes.rb:24:1:24:6 | script | +| scopes.rb:27:1:27:1 | x | +| scopes.rb:29:3:29:3 | x | +| scopes.rb:32:3:32:3 | x | +| scopes.rb:35:3:35:3 | x | +| scopes.rb:38:3:38:3 | x | | ssa.rb:1:7:1:7 | b | | ssa.rb:2:3:2:3 | i | | ssa.rb:18:8:18:8 | x | diff --git a/ql/test/library-tests/variables/varscopes.expected b/ql/test/library-tests/variables/varscopes.expected index 1cc0d4913e9..df27779ee3d 100644 --- a/ql/test/library-tests/variables/varscopes.expected +++ b/ql/test/library-tests/variables/varscopes.expected @@ -47,9 +47,14 @@ | parameters.rb:49:1:51:3 | method scope | | parameters.rb:54:9:57:3 | block scope | | scopes.rb:1:1:1:15 | method scope | -| scopes.rb:1:1:24:12 | top-level scope | +| scopes.rb:1:1:40:1 | top-level scope | | scopes.rb:2:9:6:3 | block scope | | scopes.rb:9:9:18:3 | block scope | +| scopes.rb:26:1:26:12 | class scope | +| scopes.rb:28:1:30:3 | module scope | +| scopes.rb:31:1:33:3 | class scope | +| scopes.rb:34:1:36:3 | class scope | +| scopes.rb:37:1:39:3 | method scope | | ssa.rb:1:1:16:3 | method scope | | ssa.rb:1:1:88:3 | top-level scope | | ssa.rb:18:1:23:3 | method scope |