Merge pull request #165 from github/aibaars/methods

Implement method lookup
This commit is contained in:
Arthur Baars
2021-04-21 11:24:20 +02:00
committed by GitHub
17 changed files with 614 additions and 49 deletions

View File

@@ -85,6 +85,21 @@ class MethodCall extends Call, TMethodCall {
*/
Expr getReceiver() { none() }
/**
* Holds if the receiver is `self` or there is no receiver, which has the same
* meaning as an explict `self`. For example:
*
* ```rb
* self.foo
* foo
* ```
*/
predicate receiverIsSelf() {
this.getReceiver() instanceof Self
or
not exists(this.getReceiver())
}
/**
* Gets the name of the method being called. For example, in:
*

View File

@@ -8,9 +8,18 @@ private import internal.TreeSitter
* A representation of a run-time `module` or `class` value.
*/
class Module extends TModule {
/** Get a declaration of this module, if any. */
/** Gets a declaration of this module, if any. */
ModuleBase getADeclaration() { result.getModule() = this }
/** Gets the super class of this module, if any. */
Module getSuperClass() { result = getSuperClass(this) }
/** Gets a `prepend`ed module. */
Module getAPrependedModule() { result = getAPrependedModule(this) }
/** Gets an `include`d module. */
Module getAnIncludedModule() { result = getAnIncludedModule(this) }
/** Gets a textual representation of this module. */
string toString() {
this = TResolved(result)

View File

@@ -34,6 +34,58 @@ private module Cached {
result = scopeAppend(container, n.getName())
)
}
cached
Module getSuperClass(Module cls) {
cls = TResolved("Object") and result = TResolved("BasicObject")
or
cls = TResolved("Module") and result = TResolved("Object")
or
cls = TResolved("Class") and result = TResolved("Module")
or
not cls = TResolved(builtin()) and
(
exists(ClassDeclaration d |
d = cls.getADeclaration() and
result = resolveScopeExpr(d.getSuperclassExpr())
)
or
result = TResolved("Object") and
forex(ClassDeclaration d | d = cls.getADeclaration() |
not exists(resolveScopeExpr(d.getSuperclassExpr()))
)
)
}
cached
Module getAnIncludedModule(Module m) {
m = TResolved("Object") and result = TResolved("Kernel")
or
exists(IncludeOrPrependCall c |
c.getMethodName() = "include" and
(
m = resolveScopeExpr(c.getReceiver())
or
m = enclosingModule(c).getModule() and
c.receiverIsSelf()
) and
result = resolveScopeExpr(c.getAnArgument())
)
}
cached
Module getAPrependedModule(Module m) {
exists(IncludeOrPrependCall c |
c.getMethodName() = "prepend" and
(
m = resolveScopeExpr(c.getReceiver())
or
m = enclosingModule(c).getModule() and
c.receiverIsSelf()
) and
result = resolveScopeExpr(c.getAnArgument())
)
}
}
import Cached
@@ -242,3 +294,31 @@ private string qualifiedModuleName(string container, string name) {
container = "Object" and name = result
)
}
private Module getAncestors(Module m) {
result = m or
result = getAncestors(m.getAnIncludedModule()) or
result = getAncestors(m.getAPrependedModule())
}
Method getMethod(TModule owner, string name) {
exists(ModuleBase m | m.getModule() = owner and result = m.getMethod(name))
}
private Method lookupMethod0(Module m, string name) {
result = lookupMethod0(m.getAPrependedModule(), name)
or
not exists(getMethod(getAncestors(m.getAPrependedModule()), name)) and
(
result = getMethod(m, name)
or
not exists(getMethod(m, name)) and result = lookupMethod0(m.getAnIncludedModule(), name)
)
}
Method lookupMethod(Module m, string name) {
result = lookupMethod0(m, name)
or
not exists(lookupMethod0(m, name)) and
result = lookupMethod(m.getSuperClass(), name)
}

View File

@@ -1,5 +1,6 @@
/**
* @kind graph
* @id rb/test/cfg
*/
import codeql_ruby.CFG

View File

@@ -1,5 +1,6 @@
/**
* @kind graph
* @id rb/test/print-ast
*/
import codeql_ruby.printAst

View File

@@ -101,49 +101,3 @@ modulesInModules
| modules.rb:95:1:99:3 | IncludeTest2 | modules.rb:97:3:98:5 | Z | Z |
| modules.rb:101:1:105:3 | PrependTest | modules.rb:103:3:104:5 | Y | Y |
| modules.rb:107:1:110:3 | MM | modules.rb:108:3:109:5 | MM | MM |
moduleTypes
| classes.rb:2:1:56:3 | classes.rb | file://:0:0:0:0 | Object |
| classes.rb:3:1:4:3 | Foo | modules.rb:4:1:24:3 | Foo |
| classes.rb:7:1:8:3 | Bar | modules.rb:37:1:46:3 | Bar |
| classes.rb:11:1:12:3 | Baz | classes.rb:11:1:12:3 | Baz |
| classes.rb:15:1:15:20 | MyModule | classes.rb:15:1:15:20 | MyModule |
| classes.rb:16:1:17:3 | MyClass | classes.rb:16:1:17:3 | MyModule::MyClass |
| classes.rb:20:1:37:3 | Wibble | classes.rb:20:1:37:3 | Wibble |
| classes.rb:32:3:33:5 | ClassInWibble | classes.rb:32:3:33:5 | Wibble::ClassInWibble |
| classes.rb:35:3:36:5 | ModuleInWibble | classes.rb:35:3:36:5 | Wibble::ModuleInWibble |
| classes.rb:55:1:56:3 | MyClassInGlobalScope | classes.rb:55:1:56:3 | MyClassInGlobalScope |
| modules.rb:1:1:2:3 | Empty | modules.rb:1:1:2:3 | Empty |
| modules.rb:1:1:122:1 | modules.rb | file://:0:0:0:0 | Object |
| modules.rb:4:1:24:3 | Foo | modules.rb:4:1:24:3 | Foo |
| modules.rb:5:3:14:5 | Bar | modules.rb:5:3:14:5 | Foo::Bar |
| modules.rb:6:5:7:7 | ClassInFooBar | modules.rb:6:5:7:7 | Foo::Bar::ClassInFooBar |
| modules.rb:19:3:20:5 | ClassInFoo | modules.rb:19:3:20:5 | Foo::ClassInFoo |
| modules.rb:26:1:35:3 | Foo | modules.rb:4:1:24:3 | Foo |
| modules.rb:30:3:31:5 | ClassInAnotherDefinitionOfFoo | modules.rb:30:3:31:5 | Foo::ClassInAnotherDefinitionOfFoo |
| modules.rb:37:1:46:3 | Bar | modules.rb:37:1:46:3 | Bar |
| modules.rb:48:1:57:3 | Bar | modules.rb:5:3:14:5 | Foo::Bar |
| modules.rb:49:3:50:5 | ClassInAnotherDefinitionOfFooBar | modules.rb:49:3:50:5 | Foo::Bar::ClassInAnotherDefinitionOfFooBar |
| modules.rb:60:1:61:3 | MyModuleInGlobalScope | modules.rb:60:1:61:3 | MyModuleInGlobalScope |
| modules.rb:63:1:81:3 | Test | modules.rb:63:1:81:3 | Test |
| modules.rb:65:3:68:5 | Foo1 | modules.rb:65:3:68:5 | Test::Foo1 |
| modules.rb:66:5:67:7 | Bar | modules.rb:66:5:67:7 | Test::Foo1::Bar |
| modules.rb:70:3:74:5 | Foo2 | modules.rb:70:3:74:5 | Test::Foo2 |
| modules.rb:71:5:71:19 | Foo2 | modules.rb:71:5:71:19 | Test::Foo2::Foo2 |
| modules.rb:72:5:73:7 | Bar | modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar |
| modules.rb:76:3:80:5 | Foo3 | modules.rb:76:3:80:5 | Test::Foo3 |
| modules.rb:78:5:79:7 | Bar | modules.rb:37:1:46:3 | Bar |
| modules.rb:83:1:86:3 | Other | modules.rb:83:1:86:3 | Other |
| modules.rb:84:3:85:5 | Foo1 | modules.rb:84:3:85:5 | Other::Foo1 |
| modules.rb:88:1:93:3 | IncludeTest | modules.rb:88:1:93:3 | IncludeTest |
| modules.rb:91:3:92:5 | Y | modules.rb:91:3:92:5 | Test::Foo1::Y |
| modules.rb:95:1:99:3 | IncludeTest2 | modules.rb:95:1:99:3 | IncludeTest2 |
| modules.rb:97:3:98:5 | Z | modules.rb:97:3:98:5 | Test::Foo1::Z |
| modules.rb:101:1:105:3 | PrependTest | modules.rb:101:1:105:3 | PrependTest |
| modules.rb:103:3:104:5 | Y | modules.rb:103:3:104:5 | Test::Foo2::Y |
| modules.rb:107:1:110:3 | MM | modules.rb:107:1:110:3 | MM |
| modules.rb:108:3:109:5 | MM | modules.rb:108:3:109:5 | MM::MM |
| modules.rb:112:1:113:3 | YY | modules.rb:112:1:113:3 | YY |
| modules.rb:115:1:118:3 | XX | modules.rb:115:1:118:3 | XX |
| modules.rb:116:7:117:9 | YY | modules.rb:116:7:117:9 | XX::YY |
| modules.rb:120:1:121:3 | Baz | modules.rb:120:1:121:3 | Test::Foo1::Bar::Baz |
| toplevel.rb:1:1:5:23 | toplevel.rb | file://:0:0:0:0 | Object |

View File

@@ -23,5 +23,3 @@ query predicate classesInModules(ModuleDeclaration mod, ClassDeclaration klass,
query predicate modulesInModules(ModuleDeclaration mod, ModuleDeclaration child, string name) {
child = mod.getModule(name)
}
query predicate moduleTypes(ModuleBase def, Module type) { type = def.getModule() }

View File

@@ -0,0 +1,96 @@
#-----| Object
#-----| include -> Kernel
#-----| super -> BasicObject
#-----| Class
#-----| super -> Module
#-----| Kernel
#-----| Module
#-----| super -> Object
#-----| BasicObject
hello.rb:
# 1| EnglishWords
# 11| Greeting
#-----| super -> Object
#-----| include -> EnglishWords
# 18| HelloWorld
#-----| super -> Greeting
modules.rb:
# 1| Empty
# 4| Foo
# 37| Bar
#-----| super -> Object
# 60| MyModuleInGlobalScope
# 63| Test
# 83| Other
# 88| IncludeTest
#-----| include -> Test
# 95| IncludeTest2
#-----| include -> Test
# 101| PrependTest
#-----| prepend -> Test
# 107| MM
# 112| YY
#-----| super -> Object
# 115| XX
# 5| Foo::Bar
# 19| Foo::ClassInFoo
#-----| super -> Object
# 30| Foo::ClassInAnotherDefinitionOfFoo
#-----| super -> Object
# 65| Test::Foo1
# 70| Test::Foo2
# 76| Test::Foo3
# 84| Other::Foo1
# 116| XX::YY
#-----| super -> YY
# 6| Foo::Bar::ClassInFooBar
#-----| super -> Object
# 71| Test::Foo2::Foo2
# 108| MM::MM
# 49| Foo::Bar::ClassInAnotherDefinitionOfFooBar
#-----| super -> Object
# 66| Test::Foo1::Bar
#-----| super -> Object
# 91| Test::Foo1::Y
# 97| Test::Foo1::Z
# 103| Test::Foo2::Y
# 72| Test::Foo2::Foo2::Bar
#-----| super -> Object
# 120| Test::Foo1::Bar::Baz

View File

@@ -0,0 +1,21 @@
/**
* @kind graph
* @id rb/test/ancestors
*/
import ruby
query predicate nodes(Module node, string key, string value) {
key = "semmle.label" and value = node.toString()
}
query predicate edges(Module source, Module target, string key, string value) {
key = "semmle.label" and
(
target = source.getSuperClass() and value = "super"
or
target = source.getAPrependedModule() and value = "prepend"
or
target = source.getAnIncludedModule() and value = "include"
)
}

View File

@@ -0,0 +1,22 @@
module EnglishWords
def hello
return "hello"
end
def world
return "world"
end
end
class Greeting
include EnglishWords
def message
return hello
end
end
class HelloWorld < Greeting
def message
return super + " " + world + "!"
end
end

View File

@@ -0,0 +1,26 @@
getMethod
| hello.rb:1:1:8:3 | EnglishWords | hello | hello.rb:2:5:4:7 | hello |
| hello.rb:1:1:8:3 | EnglishWords | world | hello.rb:5:5:7:7 | world |
| hello.rb:11:1:16:3 | Greeting | message | hello.rb:13:5:15:7 | message |
| hello.rb:18:1:22:3 | HelloWorld | message | hello.rb:19:5:21:7 | message |
| modules.rb:4:1:24:3 | Foo | method_in_another_definition_of_foo | modules.rb:27:3:28:5 | method_in_another_definition_of_foo |
| modules.rb:4:1:24:3 | Foo | method_in_foo | modules.rb:16:3:17:5 | method_in_foo |
| modules.rb:5:3:14:5 | Foo::Bar | method_in_another_definition_of_foo_bar | modules.rb:52:3:53:5 | method_in_another_definition_of_foo_bar |
| modules.rb:5:3:14:5 | Foo::Bar | method_in_foo_bar | modules.rb:9:5:10:7 | method_in_foo_bar |
| modules.rb:37:1:46:3 | Bar | method_a | modules.rb:38:3:39:5 | method_a |
| modules.rb:37:1:46:3 | Bar | method_b | modules.rb:41:3:42:5 | method_b |
lookupMethod
| hello.rb:1:1:8:3 | EnglishWords | hello | hello.rb:2:5:4:7 | hello |
| hello.rb:1:1:8:3 | EnglishWords | world | hello.rb:5:5:7:7 | world |
| hello.rb:11:1:16:3 | Greeting | hello | hello.rb:2:5:4:7 | hello |
| hello.rb:11:1:16:3 | Greeting | message | hello.rb:13:5:15:7 | message |
| hello.rb:11:1:16:3 | Greeting | world | hello.rb:5:5:7:7 | world |
| hello.rb:18:1:22:3 | HelloWorld | hello | hello.rb:2:5:4:7 | hello |
| hello.rb:18:1:22:3 | HelloWorld | message | hello.rb:19:5:21:7 | message |
| hello.rb:18:1:22:3 | HelloWorld | world | hello.rb:5:5:7:7 | world |
| modules.rb:4:1:24:3 | Foo | method_in_another_definition_of_foo | modules.rb:27:3:28:5 | method_in_another_definition_of_foo |
| modules.rb:4:1:24:3 | Foo | method_in_foo | modules.rb:16:3:17:5 | method_in_foo |
| modules.rb:5:3:14:5 | Foo::Bar | method_in_another_definition_of_foo_bar | modules.rb:52:3:53:5 | method_in_another_definition_of_foo_bar |
| modules.rb:5:3:14:5 | Foo::Bar | method_in_foo_bar | modules.rb:9:5:10:7 | method_in_foo_bar |
| modules.rb:37:1:46:3 | Bar | method_a | modules.rb:38:3:39:5 | method_a |
| modules.rb:37:1:46:3 | Bar | method_b | modules.rb:41:3:42:5 | method_b |

View File

@@ -0,0 +1,6 @@
import ruby
import codeql_ruby.ast.internal.Module as M
query MethodBase getMethod(Module m, string name) { result = M::getMethod(m, name) }
query MethodBase lookupMethod(Module m, string name) { result = M::lookupMethod(m, name) }

View File

@@ -0,0 +1,100 @@
getModule
| file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Class |
| file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Module |
| file://:0:0:0:0 | Object |
| hello.rb:1:1:8:3 | EnglishWords |
| hello.rb:11:1:16:3 | Greeting |
| hello.rb:18:1:22:3 | HelloWorld |
| modules.rb:1:1:2:3 | Empty |
| modules.rb:4:1:24:3 | Foo |
| modules.rb:5:3:14:5 | Foo::Bar |
| modules.rb:6:5:7:7 | Foo::Bar::ClassInFooBar |
| modules.rb:19:3:20:5 | Foo::ClassInFoo |
| modules.rb:30:3:31:5 | Foo::ClassInAnotherDefinitionOfFoo |
| modules.rb:37:1:46:3 | Bar |
| modules.rb:49:3:50:5 | Foo::Bar::ClassInAnotherDefinitionOfFooBar |
| modules.rb:60:1:61:3 | MyModuleInGlobalScope |
| modules.rb:63:1:81:3 | Test |
| modules.rb:65:3:68:5 | Test::Foo1 |
| modules.rb:66:5:67:7 | Test::Foo1::Bar |
| modules.rb:70:3:74:5 | Test::Foo2 |
| modules.rb:71:5:71:19 | Test::Foo2::Foo2 |
| modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar |
| modules.rb:76:3:80:5 | Test::Foo3 |
| modules.rb:83:1:86:3 | Other |
| modules.rb:84:3:85:5 | Other::Foo1 |
| modules.rb:88:1:93:3 | IncludeTest |
| modules.rb:91:3:92:5 | Test::Foo1::Y |
| modules.rb:95:1:99:3 | IncludeTest2 |
| modules.rb:97:3:98:5 | Test::Foo1::Z |
| modules.rb:101:1:105:3 | PrependTest |
| modules.rb:103:3:104:5 | Test::Foo2::Y |
| modules.rb:107:1:110:3 | MM |
| modules.rb:108:3:109:5 | MM::MM |
| modules.rb:112:1:113:3 | YY |
| modules.rb:115:1:118:3 | XX |
| modules.rb:116:7:117:9 | XX::YY |
| modules.rb:120:1:121:3 | Test::Foo1::Bar::Baz |
getADeclaration
| file://:0:0:0:0 | Object | hello.rb:1:1:22:3 | hello.rb |
| file://:0:0:0:0 | Object | modules.rb:1:1:122:1 | modules.rb |
| hello.rb:1:1:8:3 | EnglishWords | hello.rb:1:1:8:3 | EnglishWords |
| hello.rb:11:1:16:3 | Greeting | hello.rb:11:1:16:3 | Greeting |
| hello.rb:18:1:22:3 | HelloWorld | hello.rb:18:1:22:3 | HelloWorld |
| modules.rb:1:1:2:3 | Empty | modules.rb:1:1:2:3 | Empty |
| modules.rb:4:1:24:3 | Foo | modules.rb:4:1:24:3 | Foo |
| modules.rb:4:1:24:3 | Foo | modules.rb:26:1:35:3 | Foo |
| modules.rb:5:3:14:5 | Foo::Bar | modules.rb:5:3:14:5 | Bar |
| modules.rb:5:3:14:5 | Foo::Bar | modules.rb:48:1:57:3 | Bar |
| modules.rb:6:5:7:7 | Foo::Bar::ClassInFooBar | modules.rb:6:5:7:7 | ClassInFooBar |
| modules.rb:19:3:20:5 | Foo::ClassInFoo | modules.rb:19:3:20:5 | ClassInFoo |
| modules.rb:30:3:31:5 | Foo::ClassInAnotherDefinitionOfFoo | modules.rb:30:3:31:5 | ClassInAnotherDefinitionOfFoo |
| modules.rb:37:1:46:3 | Bar | modules.rb:37:1:46:3 | Bar |
| modules.rb:37:1:46:3 | Bar | modules.rb:78:5:79:7 | Bar |
| modules.rb:49:3:50:5 | Foo::Bar::ClassInAnotherDefinitionOfFooBar | modules.rb:49:3:50:5 | ClassInAnotherDefinitionOfFooBar |
| modules.rb:60:1:61:3 | MyModuleInGlobalScope | modules.rb:60:1:61:3 | MyModuleInGlobalScope |
| modules.rb:63:1:81:3 | Test | modules.rb:63:1:81:3 | Test |
| modules.rb:65:3:68:5 | Test::Foo1 | modules.rb:65:3:68:5 | Foo1 |
| modules.rb:66:5:67:7 | Test::Foo1::Bar | modules.rb:66:5:67:7 | Bar |
| modules.rb:70:3:74:5 | Test::Foo2 | modules.rb:70:3:74:5 | Foo2 |
| modules.rb:71:5:71:19 | Test::Foo2::Foo2 | modules.rb:71:5:71:19 | Foo2 |
| modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar | modules.rb:72:5:73:7 | Bar |
| modules.rb:76:3:80:5 | Test::Foo3 | modules.rb:76:3:80:5 | Foo3 |
| modules.rb:83:1:86:3 | Other | modules.rb:83:1:86:3 | Other |
| modules.rb:84:3:85:5 | Other::Foo1 | modules.rb:84:3:85:5 | Foo1 |
| modules.rb:88:1:93:3 | IncludeTest | modules.rb:88:1:93:3 | IncludeTest |
| modules.rb:91:3:92:5 | Test::Foo1::Y | modules.rb:91:3:92:5 | Y |
| modules.rb:95:1:99:3 | IncludeTest2 | modules.rb:95:1:99:3 | IncludeTest2 |
| modules.rb:97:3:98:5 | Test::Foo1::Z | modules.rb:97:3:98:5 | Z |
| modules.rb:101:1:105:3 | PrependTest | modules.rb:101:1:105:3 | PrependTest |
| modules.rb:103:3:104:5 | Test::Foo2::Y | modules.rb:103:3:104:5 | Y |
| modules.rb:107:1:110:3 | MM | modules.rb:107:1:110:3 | MM |
| modules.rb:108:3:109:5 | MM::MM | modules.rb:108:3:109:5 | MM |
| modules.rb:112:1:113:3 | YY | modules.rb:112:1:113:3 | YY |
| modules.rb:115:1:118:3 | XX | modules.rb:115:1:118:3 | XX |
| modules.rb:116:7:117:9 | XX::YY | modules.rb:116:7:117:9 | YY |
| modules.rb:120:1:121:3 | Test::Foo1::Bar::Baz | modules.rb:120:1:121:3 | Baz |
getSuperClass
| file://:0:0:0:0 | Class | file://:0:0:0:0 | Module |
| file://:0:0:0:0 | Module | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | Object | file://:0:0:0:0 | BasicObject |
| hello.rb:11:1:16:3 | Greeting | file://:0:0:0:0 | Object |
| hello.rb:18:1:22:3 | HelloWorld | hello.rb:11:1:16:3 | Greeting |
| modules.rb:6:5:7:7 | Foo::Bar::ClassInFooBar | file://:0:0:0:0 | Object |
| modules.rb:19:3:20:5 | Foo::ClassInFoo | file://:0:0:0:0 | Object |
| modules.rb:30:3:31:5 | Foo::ClassInAnotherDefinitionOfFoo | file://:0:0:0:0 | Object |
| modules.rb:37:1:46:3 | Bar | file://:0:0:0:0 | Object |
| modules.rb:49:3:50:5 | Foo::Bar::ClassInAnotherDefinitionOfFooBar | file://:0:0:0:0 | Object |
| modules.rb:66:5:67:7 | Test::Foo1::Bar | file://:0:0:0:0 | Object |
| modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar | file://:0:0:0:0 | Object |
| modules.rb:112:1:113:3 | YY | file://:0:0:0:0 | Object |
| modules.rb:116:7:117:9 | XX::YY | modules.rb:112:1:113:3 | YY |
getAPrependedModule
| modules.rb:101:1:105:3 | PrependTest | modules.rb:63:1:81:3 | Test |
getAnIncludedModule
| file://:0:0:0:0 | Object | file://:0:0:0:0 | Kernel |
| hello.rb:11:1:16:3 | Greeting | hello.rb:1:1:8:3 | EnglishWords |
| modules.rb:88:1:93:3 | IncludeTest | modules.rb:63:1:81:3 | Test |
| modules.rb:95:1:99:3 | IncludeTest2 | modules.rb:63:1:81:3 | Test |

View File

@@ -0,0 +1,11 @@
import ruby
query Module getModule() { any() }
query ModuleBase getADeclaration(Module m) { result = m.getADeclaration() }
query Module getSuperClass(Module m) { result = m.getSuperClass() }
query Module getAPrependedModule(Module m) { result = m.getAPrependedModule() }
query Module getAnIncludedModule(Module m) { result = m.getAnIncludedModule() }

View File

@@ -0,0 +1,122 @@
module Empty
end
module Foo
module Bar
class ClassInFooBar
end
def method_in_foo_bar
end
puts 'module Foo::Bar'
$global_var = 0
end
def method_in_foo
end
class ClassInFoo
end
puts 'module Foo'
$global_var = 1
end
module Foo
def method_in_another_definition_of_foo
end
class ClassInAnotherDefinitionOfFoo
end
puts 'module Foo again'
$global_var = 2
end
module Bar
def method_a
end
def method_b
end
puts 'module Bar'
$global_var = 3
end
module Foo::Bar
class ClassInAnotherDefinitionOfFooBar
end
def method_in_another_definition_of_foo_bar
end
puts 'module Foo::Bar again'
$global_var = 4
end
# a module where the name is a scope resolution using the global scope
module ::MyModuleInGlobalScope
end
module Test
module Foo1
class Foo1::Bar
end
end
module Foo2
module Foo2 end
class Foo2::Bar
end
end
module Foo3
Foo3 = Object
class Foo3::Bar
end
end
end
module Other
module Foo1
end
end
module IncludeTest
include ::Test
Object.module_eval { prepend Other }
module Foo1::Y
end
end
module IncludeTest2
include Test
module Foo1::Z
end
end
module PrependTest
prepend ::Test
module Foo2::Y
end
end
module MM
module MM::MM
end
end
class YY
end
module XX
class YY < YY
end
end
module Test::Foo1::Bar::Baz
end

View File

@@ -0,0 +1,91 @@
#-----| Object
#-----| -> BasicObject
#-----| Class
#-----| -> Module
#-----| Kernel
#-----| Module
#-----| -> Object
#-----| BasicObject
hello.rb:
# 1| EnglishWords
# 11| Greeting
#-----| -> Object
# 18| HelloWorld
#-----| -> Greeting
modules.rb:
# 1| Empty
# 4| Foo
# 37| Bar
#-----| -> Object
# 60| MyModuleInGlobalScope
# 63| Test
# 83| Other
# 88| IncludeTest
# 95| IncludeTest2
# 101| PrependTest
# 107| MM
# 112| YY
#-----| -> Object
# 115| XX
# 5| Foo::Bar
# 19| Foo::ClassInFoo
#-----| -> Object
# 30| Foo::ClassInAnotherDefinitionOfFoo
#-----| -> Object
# 65| Test::Foo1
# 70| Test::Foo2
# 76| Test::Foo3
# 84| Other::Foo1
# 116| XX::YY
#-----| -> YY
# 6| Foo::Bar::ClassInFooBar
#-----| -> Object
# 71| Test::Foo2::Foo2
# 108| MM::MM
# 49| Foo::Bar::ClassInAnotherDefinitionOfFooBar
#-----| -> Object
# 66| Test::Foo1::Bar
#-----| -> Object
# 91| Test::Foo1::Y
# 97| Test::Foo1::Z
# 103| Test::Foo2::Y
# 72| Test::Foo2::Foo2::Bar
#-----| -> Object
# 120| Test::Foo1::Bar::Baz

View File

@@ -0,0 +1,12 @@
/**
* @kind graph
* @id rb/test/supertypes
*/
import ruby
query predicate nodes(Module node, string key, string value) {
key = "semmle.label" and value = node.toString()
}
query predicate edges(Module source, Module target) { target = source.getSuperClass() }