diff --git a/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.expected b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.expected new file mode 100644 index 000000000000..979cc77777b7 --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.expected @@ -0,0 +1,10 @@ +models +edges +| implicit_return.rb:12:3:12:11 | call to source | implicit_return.rb:15:6:15:11 | call to m_body | provenance | | +nodes +| implicit_return.rb:12:3:12:11 | call to source | semmle.label | call to source | +| implicit_return.rb:15:6:15:11 | call to m_body | semmle.label | call to m_body | +subpaths +testFailures +#select +| implicit_return.rb:15:6:15:11 | call to m_body | implicit_return.rb:12:3:12:11 | call to source | implicit_return.rb:15:6:15:11 | call to m_body | $@ | implicit_return.rb:12:3:12:11 | call to source | call to source | diff --git a/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.ql b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.ql new file mode 100644 index 000000000000..fae4b68cda0e --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.ql @@ -0,0 +1,12 @@ +/** + * @kind path-problem + */ + +import codeql.ruby.AST +import utils.test.InlineFlowTest +import DefaultFlowTest +import ValueFlow::PathGraph + +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) +select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb new file mode 100644 index 000000000000..2ea215902f02 --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb @@ -0,0 +1,68 @@ +# Tests for implicit return steps in Ruby data flow. +# +# An implicit return is when no `return` statement is used; instead the +# last evaluated expression is returned. +# +# The following cases test the behaviour when the returned value is +# in the main body, a `rescue` clause, or an `else` clause, +# with and without an `ensure` clause present. + +# Simple implicit return from the method body. +def m_body + source(1) +end + +sink(m_body) # $ hasValueFlow=1 + +# Implicit return from the method body when an `ensure` clause is present. +def m_body_ensure + source(2) +ensure + source(20) +end + +sink(m_body_ensure) # $ MISSING: hasValueFlow=2 + +# Implicit return from a `rescue` clause. +def m_rescue + raise "error" +rescue + source(3) +end + +sink(m_rescue) # $ MISSING: hasValueFlow=3 + +# Implicit return from a `rescue` clause when an `ensure` clause is present. +def m_rescue_ensure + raise "error" +rescue + source(4) +ensure + source(40) +end + +sink(m_rescue_ensure) # $ MISSING: hasValueFlow=4 + +# Implicit return from an `else` clause. +def m_else + source(50) +rescue + nil +else + source(5) +end + +sink(m_else) # $ MISSING: hasValueFlow=5 + +# Implicit return from an `else` clause when an `ensure` clause is present. +def m_else_ensure + source(60) +rescue + nil +else + source(6) +ensure + nil +end + +sink(m_else_ensure) # $ MISSING: hasValueFlow=6