diff --git a/ql/src/codeql_ruby/ast/Variable.qll b/ql/src/codeql_ruby/ast/Variable.qll index 73b4e2a0593..06dee5ef89b 100644 --- a/ql/src/codeql_ruby/ast/Variable.qll +++ b/ql/src/codeql_ruby/ast/Variable.qll @@ -53,30 +53,47 @@ class Variable extends TVariable { } /** A local variable. */ -class LocalVariable extends Variable { +class LocalVariable extends Variable, TLocalVariable { override LocalVariable::Range range; final override LocalVariableAccess getAnAccess() { result.getVariable() = this } } +/** A global variable. */ +class GlobalVariable extends Variable, TGlobalVariable { + override GlobalVariable::Range range; + + final override GlobalVariableAccess getAnAccess() { result.getVariable() = this } +} + /** An access to a variable. */ -class VariableAccess extends Expr, @token_identifier { +class VariableAccess extends Expr { override VariableAccess::Range range; /** Gets the variable this identifier refers to. */ Variable getVariable() { result = range.getVariable() } final override string toString() { result = this.getVariable().getName() } - // TODO uncomment this and fix the params test - //override string getAPrimaryQlClass() { result = "VariableAccess" } } /** An access to a local variable. */ -class LocalVariableAccess extends VariableAccess { +class LocalVariableAccess extends VariableAccess, @token_identifier { final override LocalVariableAccess::Range range; /** Gets the variable this identifier refers to. */ final override LocalVariable getVariable() { result = range.getVariable() } - // TODO uncomment this and fix the params test - //final override string getAPrimaryQlClass() { result = "LocalVariableAccess" } + + final override string getAPrimaryQlClass() { + not this instanceof SimpleParameter and result = "LocalVariableAccess" + } +} + +/** An access to a local variable. */ +class GlobalVariableAccess extends VariableAccess, @token_global_variable { + final override GlobalVariableAccess::Range range; + + /** Gets the variable this identifier refers to. */ + final override GlobalVariable getVariable() { result = range.getVariable() } + + final override string getAPrimaryQlClass() { result = "GlobalVariableAccess" } } diff --git a/ql/src/codeql_ruby/ast/internal/Variable.qll b/ql/src/codeql_ruby/ast/internal/Variable.qll index a1fd920231a..8ef650ff1cf 100644 --- a/ql/src/codeql_ruby/ast/internal/Variable.qll +++ b/ql/src/codeql_ruby/ast/internal/Variable.qll @@ -101,6 +101,7 @@ cached private module Cached { cached newtype TScope = + TGlobalScope() or TTopLevelScope(Generated::Program node) or TModuleScope(Generated::Module node) or TClassScope(AstNode cls) { @@ -110,6 +111,7 @@ private module Cached { cached newtype TVariable = + TGlobalVariable(string name) { name = any(Generated::GlobalVariable var).getValue() } or TLocalVariable(VariableScope scope, string name, Generated::Identifier i) { scopeDefinesParameterVariable(scope, name, i) or @@ -153,6 +155,14 @@ module VariableScope { } } +module GlobalScope { + class Range extends VariableScope::Range, TGlobalScope { + override string toString() { result = "global scope" } + + override AstNode getScopeElement() { none() } + } +} + module TopLevelScope { class Range extends VariableScope::Range, TTopLevelScope { override string toString() { result = "top-level scope" } @@ -211,7 +221,7 @@ module Variable { } module LocalVariable { - class Range extends Variable::Range { + class Range extends Variable::Range, TLocalVariable { private VariableScope scope; private string name; private Generated::Identifier i; @@ -226,21 +236,43 @@ module LocalVariable { } } +module GlobalVariable { + class Range extends Variable::Range, TGlobalVariable { + private string name; + + Range() { this = TGlobalVariable(name) } + + final override string getName() { result = name } + + final override Location getLocation() { none() } + + final override VariableScope getDeclaringScope() { result = TGlobalScope() } + } +} + module VariableAccess { - class Range extends Expr::Range, @token_identifier { - override Generated::Identifier generated; - Variable variable; - - Range() { access(this, variable) } - - Variable getVariable() { result = variable } + abstract class Range extends Expr::Range { + abstract Variable getVariable(); } } module LocalVariableAccess { - class Range extends VariableAccess::Range { - override LocalVariable variable; + class Range extends VariableAccess::Range, @token_identifier { + override Generated::Identifier generated; + LocalVariable variable; - override LocalVariable getVariable() { result = variable } + Range() { access(this, variable) } + + final override LocalVariable getVariable() { result = variable } + } +} + +module GlobalVariableAccess { + class Range extends VariableAccess::Range, @token_global_variable { + GlobalVariable variable; + + Range() { this.(Generated::GlobalVariable).getValue() = variable.getName() } + + final override GlobalVariable getVariable() { result = variable } } } diff --git a/ql/test/library-tests/variables/scopes.rb b/ql/test/library-tests/variables/scopes.rb index 1219acef8cc..65816cc31b4 100644 --- a/ql/test/library-tests/variables/scopes.rb +++ b/ql/test/library-tests/variables/scopes.rb @@ -15,4 +15,10 @@ puts a puts b # new local variable puts c # new local variable puts d # new local variable -end \ No newline at end of file +end + +# new global variable +$global = 42 + +# use of a pre-defined global variable +script = $0 diff --git a/ql/test/library-tests/variables/varaccess.expected b/ql/test/library-tests/variables/varaccess.expected index 3c97574dacf..43683ab605d 100644 --- a/ql/test/library-tests/variables/varaccess.expected +++ b/ql/test/library-tests/variables/varaccess.expected @@ -76,17 +76,20 @@ | 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:18:3 | top-level scope | -| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:18:3 | top-level 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: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:18:3 | top-level scope | -| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:18:3 | top-level scope | -| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:18:3 | top-level scope | -| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:18:3 | top-level 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: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:18:3 | top-level 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: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:10:24:11 | $0 | file://:0:0:0:0 | $0 | file://:0:0:0:0 | global scope | diff --git a/ql/test/library-tests/variables/variable.expected b/ql/test/library-tests/variables/variable.expected index 143f5d2639a..749df84cb0d 100644 --- a/ql/test/library-tests/variables/variable.expected +++ b/ql/test/library-tests/variables/variable.expected @@ -1,3 +1,5 @@ +| file://:0:0:0:0 | $0 | +| file://:0:0:0:0 | $global | | nested_scopes.rb:5:3:5:3 | a | | nested_scopes.rb:7:5:7:5 | a | | nested_scopes.rb:9:7:9:7 | a | @@ -40,3 +42,4 @@ | scopes.rb:13:7:13:7 | b | | scopes.rb:13:11:13:11 | c | | scopes.rb:13:14:13:14 | d | +| scopes.rb:24:1:24:6 | script | diff --git a/ql/test/library-tests/variables/varscopes.expected b/ql/test/library-tests/variables/varscopes.expected index 70c2d9283cf..03b586db730 100644 --- a/ql/test/library-tests/variables/varscopes.expected +++ b/ql/test/library-tests/variables/varscopes.expected @@ -1,3 +1,4 @@ +| file://:0:0:0:0 | global scope | | nested_scopes.rb:1:1:3:3 | method scope | | nested_scopes.rb:1:1:42:1 | top-level scope | | nested_scopes.rb:4:1:39:3 | class scope | @@ -25,6 +26,6 @@ | 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:18:3 | top-level scope | +| scopes.rb:1:1:24:12 | top-level scope | | scopes.rb:2:9:6:3 | block scope | | scopes.rb:9:9:18:3 | block scope |